001/* 002 * Copyright 2010, 2011 Christopher Pheby 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.jadira.bindings.core.utils.reflection; 017 018import java.util.HashMap; 019import java.util.Map; 020 021import org.jadira.bindings.core.utils.string.StringUtils; 022 023/** 024 * Holds utility methods for obtaining a class from a symbolic representation 025 * The result of {@link #determineQualifiedName(String)} is equivalent in format to the result of {@link Class#getName()} 026 */ 027public final class ClassUtils { 028 029 public static final char PACKAGE_SEPARATOR_CHARACTER = '.'; 030 public static final char INNER_CLASS_SEPARATOR_CHAR = '$'; 031 032 private static final Map<String, String> PRIMITIVE_MAPPING = new HashMap<String, String>(); 033 034 static { 035 PRIMITIVE_MAPPING.put("int", "I"); 036 PRIMITIVE_MAPPING.put("boolean", "Z"); 037 PRIMITIVE_MAPPING.put("float", "F"); 038 PRIMITIVE_MAPPING.put("long", "J"); 039 PRIMITIVE_MAPPING.put("short", "S"); 040 PRIMITIVE_MAPPING.put("byte", "B"); 041 PRIMITIVE_MAPPING.put("double", "D"); 042 PRIMITIVE_MAPPING.put("char", "C"); 043 } 044 045 private ClassUtils() { 046 } 047 048 /** 049 * Attempt to load the class matching the given qualified name. 050 * Uses the current Thread's class loader, or if unavailable, the classloader 051 * this class was loaded from. 052 * @param qualifiedName The qualified name to use 053 * @throws IllegalArgumentException If the class cannot be loaded 054 * @return The {@link Class} representing the given class 055 */ 056 public static Class<?> getClass(String qualifiedName) { 057 return getClass(ClassLoaderUtils.getClassLoader(), qualifiedName); 058 } 059 060 /** 061 * Attempt to load the class matching the given qualified name 062 * @param classLoader Classloader to use 063 * @param className The classname to use 064 * @throws IllegalArgumentException If the class cannot be loaded 065 * @return The {@link Class} representing the given class 066 */ 067 public static Class<?> getClass(ClassLoader classLoader, String className) { 068 try { 069 070 final Class<?> clazz; 071 072 if (PRIMITIVE_MAPPING.containsKey(className)) { 073 074 String qualifiedName = "[" + PRIMITIVE_MAPPING.get(className); 075 clazz = Class.forName(qualifiedName, true, classLoader).getComponentType(); 076 } else { 077 clazz = Class.forName(determineQualifiedName(className), true, classLoader); 078 } 079 return clazz; 080 } catch (ClassNotFoundException ex) { 081 082 int lastSeparatorIndex = className.lastIndexOf(PACKAGE_SEPARATOR_CHARACTER); 083 084 if (lastSeparatorIndex != -1) { 085 return getClass(classLoader, className.substring(0, lastSeparatorIndex) + INNER_CLASS_SEPARATOR_CHAR 086 + className.substring(lastSeparatorIndex + 1)); 087 } 088 throw new IllegalArgumentException("Unable to unmarshall String to Class: " + className); 089 } 090 } 091 092 /** 093 * Given a readable class name determine the JVM Qualified Name 094 * @param className The name to convert 095 * @return The JVM Qualified representation 096 */ 097 public static String determineQualifiedName(String className) { 098 099 String readableClassName = StringUtils.removeWhitespace(className); 100 if (readableClassName == null) { 101 102 throw new IllegalArgumentException("readableClassName must not be null."); 103 104 } else if (readableClassName.endsWith("[]")) { 105 106 StringBuilder classNameBuffer = new StringBuilder(); 107 108 while (readableClassName.endsWith("[]")) { 109 readableClassName = readableClassName.substring(0, readableClassName.length() - 2); 110 classNameBuffer.append("["); 111 } 112 113 String abbreviation = PRIMITIVE_MAPPING.get(readableClassName); 114 115 if (abbreviation == null) { 116 classNameBuffer.append("L").append(readableClassName).append(";"); 117 } else { 118 classNameBuffer.append(abbreviation); 119 } 120 121 readableClassName = classNameBuffer.toString(); 122 } 123 return readableClassName; 124 } 125 126 /** 127 * Given a JVM Qualified Name produce a readable classname 128 * @param qualifiedName The Qualified Name 129 * @return The readable classname 130 */ 131 public static String determineReadableClassName(String qualifiedName) { 132 133 String readableClassName = StringUtils.removeWhitespace(qualifiedName); 134 if (readableClassName == null) { 135 136 throw new IllegalArgumentException("qualifiedName must not be null."); 137 } else if (readableClassName.startsWith("[")) { 138 139 StringBuilder classNameBuffer = new StringBuilder(); 140 while (readableClassName.startsWith("[")) { 141 classNameBuffer.append("[]"); 142 readableClassName = readableClassName.substring(1); 143 } 144 145 if (PRIMITIVE_MAPPING.containsValue(readableClassName)) { 146 147 for (Map.Entry<String,String> next : PRIMITIVE_MAPPING.entrySet()) { 148 if (next.getValue().equals(readableClassName)) { 149 readableClassName = next.getKey() + classNameBuffer.toString(); 150 break; 151 } 152 } 153 154 } else if (readableClassName.startsWith("L") && readableClassName.endsWith(";")) { 155 readableClassName = readableClassName.substring(1, readableClassName.length() - 1) + classNameBuffer.toString(); 156 } else { 157 throw new IllegalArgumentException("qualifiedName was invalid {" + readableClassName + "}"); 158 } 159 } else if (readableClassName.endsWith("]")) { 160 throw new IllegalArgumentException("qualifiedName was invalid {" + readableClassName + "}"); 161 } 162 163 return readableClassName; 164 } 165}