001/*
002 *  Licensed to the Apache Software Foundation (ASF) under one
003 *  or more contributor license agreements.  See the NOTICE file
004 *  distributed with this work for additional information
005 *  regarding copyright ownership.  The ASF licenses this file
006 *  to you under the Apache License, Version 2.0 (the
007 *  "License"); you may not use this file except in compliance
008 *  with the License.  You may obtain a copy of the License at
009 *
010 *        http://www.apache.org/licenses/LICENSE-2.0
011 *
012 *  Unless required by applicable law or agreed to in writing,
013 *  software distributed under the License is distributed on an
014 *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 *  KIND, either express or implied.  See the License for the
016 *  specific language governing permissions and limitations
017 *  under the License.
018 */
019
020package org.apache.isis.core.commons.lang;
021
022import java.util.Arrays;
023import java.util.HashMap;
024import java.util.List;
025import java.util.Map;
026
027import com.google.common.collect.Maps;
028
029public final class ClassUtil {
030
031    static final String JAVA_CLASS_PREFIX = "java.";
032
033    private static Map<String, Class<?>> builtInClasses = new HashMap<String, Class<?>>();
034
035    static {
036        put(void.class);
037        put(boolean.class);
038        put(char.class);
039        put(byte.class);
040        put(short.class);
041        put(int.class);
042        put(long.class);
043        put(float.class);
044        put(double.class);
045    }
046
047    private static void put(final Class<?> cls) {
048        builtInClasses.put(cls.getName(), cls);
049    }
050
051    static final Map<Class<?>, Object> defaultByPrimitiveClass = 
052            MapUtil.asMap(
053                boolean.class, false,
054                byte.class, (byte)0,
055                short.class, (short)0,
056                int.class, 0,
057                long.class, 0L,
058                float.class, 0.0f,
059                double.class, 0.0,
060                char.class, (char)0
061            );
062    static Map<Class<?>, Class<?>> wrapperClasses = 
063        MapUtil.asMap(
064            // TODO: there is a better way of doing this in 1.6 using TypeMirror
065            boolean.class, Boolean.class,
066            byte.class, Byte.class,
067            char.class, Character.class,
068            short.class, Short.class,
069            int.class, Integer.class,
070            long.class, Long.class,
071            float.class, Float.class,
072            double.class, Double.class,
073            void.class, Void.class
074        );
075        
076    static Map<Class<?>, Object> defaultByPrimitiveType = new HashMap<Class<?>, Object>();
077    
078    static {
079        defaultByPrimitiveType.put(byte.class, (byte) 0);
080        defaultByPrimitiveType.put(short.class, (short) 0);
081        defaultByPrimitiveType.put(int.class, 0);
082        defaultByPrimitiveType.put(long.class, 0L);
083        defaultByPrimitiveType.put(char.class, 0);
084        defaultByPrimitiveType.put(float.class, 0.0F);
085        defaultByPrimitiveType.put(double.class, 0.0);
086        defaultByPrimitiveType.put(boolean.class, false);
087    }
088    
089    public static Map<String, Class<?>> primitives = Maps.newHashMap();
090
091    static {
092        @SuppressWarnings({ "rawtypes" })
093        final List<Class> primitiveClasses = Arrays.<Class> asList(
094                boolean.class, 
095                byte.class, 
096                short.class, 
097                int.class, 
098                long.class, 
099                float.class, 
100                double.class, 
101                char.class);
102        for (final Class<?> cls : primitiveClasses) {
103            primitives.put(cls.getName(), cls);
104        }
105    }
106
107    
108    // //////////////////////////////////////
109
110    
111    
112    private ClassUtil() {
113    }
114
115    public static Class<?> getBuiltIn(final String name) {
116        return builtInClasses.get(name);
117    }
118
119    /**
120     * Returns the supplied Class so long as it implements (or is a subclass of)
121     * the required class, and also has either a constructor accepting the
122     * specified param type, or has a no-arg constructor.
123     */
124    public static Class<?> implementingClassOrNull(final String classCandidateName, final Class<?> requiredClass, final Class<?> constructorParamType) {
125        if (classCandidateName == null) {
126            return null;
127        }
128        Class<?> classCandidate = null;
129        try {
130            classCandidate = Class.forName(classCandidateName);
131            return ClassExtensions.implementingClassOrNull(classCandidate, requiredClass, constructorParamType);
132        } catch (final ClassNotFoundException e) {
133            return null;
134        }
135    }
136
137    public static boolean directlyImplements(final Class<?> cls, final Class<?> interfaceType) {
138        for (final Class<?> directlyImplementedInterface : cls.getInterfaces()) {
139            if (directlyImplementedInterface == interfaceType) {
140                return true;
141            }
142        }
143        return false;
144    }
145
146    public static boolean directlyImplements(final Class<?> extendee, final String interfaceTypeName) {
147        try {
148            final Class<?> interfaceType = Thread.currentThread().getContextClassLoader().loadClass(interfaceTypeName);
149            return directlyImplements(extendee, interfaceType);
150        } catch (ClassNotFoundException e) {
151            throw new RuntimeException(e);
152        }
153    }
154
155    public static Class<?> forName(final String fullName) {
156        final Class<?> primitiveCls = primitives.get(fullName);
157        if (primitiveCls != null) {
158            return primitiveCls;
159        }
160        try {
161            return Thread.currentThread().getContextClassLoader().loadClass(fullName);
162        } catch (final ClassNotFoundException e) {
163            throw new RuntimeException(e);
164        }
165    }
166
167    public static Class<?> forNameElseNull(final String fullName) {
168        if (fullName == null) {
169            return null;
170        }
171        try {
172            return Thread.currentThread().getContextClassLoader().loadClass(fullName);
173        } catch (final ClassNotFoundException e) {
174            return null;
175        }
176    }
177
178}