/* * Copyright (c) 2009, SQL Power Group Inc. * * This file is part of SQL Power Library. * * SQL Power Library is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * SQL Power Library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package ca.sqlpower.object.annotation; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; import ca.sqlpower.dao.helper.SPPersisterHelper; import ca.sqlpower.object.SPObject; import com.sun.mirror.declaration.TypeDeclaration; import com.sun.mirror.type.ClassType; import com.sun.mirror.type.InterfaceType; import com.sun.mirror.type.PrimitiveType; import com.sun.mirror.type.TypeMirror; import com.sun.mirror.type.PrimitiveType.Kind; import com.sun.mirror.type.ArrayType; public class SPAnnotationProcessorUtils { private SPAnnotationProcessorUtils() { // Should not instantiate an instance of this class as all methods are static. } /** * Converts a primitive data type to the equivalent {@link Class} type. * * @param kind * The {@link PrimitiveType.Kind} to convert. * @return The equivalent {@link Class} of the primitive type. */ public static Class<?> convertPrimitiveToClass(Kind kind) { if (kind.equals(Kind.BOOLEAN)) { return Boolean.class; } else if (kind.equals(Kind.BYTE)) { return Byte.class; } else if (kind.equals(Kind.CHAR)) { return Character.class; } else if (kind.equals(Kind.DOUBLE)) { return Double.class; } else if (kind.equals(Kind.FLOAT)) { return Float.class; } else if (kind.equals(Kind.INT)) { return Integer.class; } else if (kind.equals(Kind.LONG)) { return Long.class; } else if (kind.equals(Kind.SHORT)) { return Short.class; } else { throw new IllegalStateException("The PrimitiveType Kind " + kind.name() + " is not recognized. This exception " + "should never be thrown."); } } /** * Converts a primitive, class or interface {@link TypeMirror} to an actual * class instance. * * @param type * The {@link TypeMirror} to convert. * @return The class instance of the converted {@link TypeMirror}. * @throws ClassNotFoundException * Thrown if the class instance of a class/interface * {@link TypeMirror} could not be found. */ public static Class<?> convertTypeMirrorToClass(TypeMirror type) throws ClassNotFoundException { if (type instanceof PrimitiveType) { return convertPrimitiveToClass(((PrimitiveType) type).getKind()); } else if (type instanceof ClassType) { String qualifiedName = convertTypeDeclarationToQualifiedName(((ClassType) type).getDeclaration()); return Class.forName(qualifiedName); } else if (type instanceof InterfaceType) { String qualifiedName = convertTypeDeclarationToQualifiedName(((InterfaceType) type).getDeclaration()); return Class.forName(qualifiedName); } else if (type instanceof ArrayType) { String qualifiedName = "[L" + convertTypeMirrorToClass(((ArrayType) type).getComponentType()).getName() + ";"; return Class.forName(qualifiedName); } else { return null; } } /** * Converts a JavaBean formatted method name to a property name. * * @param methodName * The JavaBean formatted method name. This method name must * start with either "is", "get", or "set" and there must be * characters following after it. * @return The converted property name. * @throws IllegalArgumentException * Thrown if the given method name does not follow the JavaBean * format. */ public static String convertMethodToProperty(String methodName) throws IllegalArgumentException { String propertyName; if (methodName.length() > 2 && methodName.startsWith("is")) { propertyName = methodName.substring(2); } else if (methodName.length() > 3 && (methodName.startsWith("get") || methodName.startsWith("set"))) { propertyName = methodName.substring(3); } else { throw new IllegalArgumentException("Cannot convert method name \"" + methodName + "\" to property name as it is not a valid JavaBean name."); } if (!propertyName.equals("UUID")) { propertyName = propertyName.substring(0, 1).toLowerCase() + ((propertyName.length() > 1)? propertyName.substring(1) : ""); } return propertyName; } /** * Converts a property name to its JavaBean getter method name depending on * what type the property is. * * @param propertyName * The property name to convert to its JavaBean getter method * name. * @param type * The parent type that we are looking for accessors on. * @return The JavaBean getter method name. If the property type is a * {@link Boolean} value, then the getter method name is prefixed * with "is" or "get" depending on the method found. Otherwise, it * is prefixed with "get". If no accessor is found an exception will * be thrown. */ public static String convertPropertyToAccessor(String propertyName, Class<?> type) { String regex = "(get|is)"; for (char c : propertyName.toCharArray()) { String stringC = new String(new char[]{c}); regex += "[" + stringC.toLowerCase() + stringC.toUpperCase() + "]"; } List<String> methodNames = new ArrayList<String>(); for (Method m : type.getMethods()) { methodNames.add(m.getName()); if (m.getName().matches(regex)) { return m.getName(); } } throw new IllegalArgumentException("The class " + type + " does not have an accessor for property \"" + propertyName +"\"."); } /** * Converts an {@link SPObject} class to a suitable * {@link SPPersisterHelper} field name. This is essentially the simple name * of the class but prepended with "helperFor". * * @param clazz * The {@link SPObject} class to convert. * @return The field name corresponding to the given {@link SPObject} class. */ public static String convertClassToFieldName(Class<? extends SPObject> clazz) { return "helperFor" + clazz.getSimpleName(); } /** * Converts a {@link TypeDeclaration} to its qualified name. This qualified * name will correctly convert "." to "$" for nested classes, enums, etc. * * @param td * The {@link TypeDeclaration} to convert. * @return The qualified name of the given {@link TypeDeclaration}. */ public static String convertTypeDeclarationToQualifiedName(TypeDeclaration td) { TypeDeclaration declaringType = td; while (declaringType.getDeclaringType() != null) { declaringType = declaringType.getDeclaringType(); } String topLevelName = declaringType.getQualifiedName(); String qualifiedName; if (td == declaringType) { qualifiedName = topLevelName; } else { String suffix = td.getQualifiedName().substring(topLevelName.length()); qualifiedName = topLevelName + suffix.replaceAll("\\.", "\\$"); } return qualifiedName; } }