package org.hotswap.agent.util.signature; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import org.hotswap.agent.javassist.bytecode.Descriptor; /** * CtClassSignature. Creates signature for given java class * * @author Erki Ehtla, Vladimir Dvorak */ public class JavaClassSignature extends ClassSignatureBase { private Class<?> clazz; public JavaClassSignature(Class<?> clazz) { this.clazz = clazz; } @Override public String getValue() throws Exception { List<String> strings = new ArrayList<>(); if (hasElement(ClassSignatureElement.METHOD)) { boolean usePrivateMethod = hasElement(ClassSignatureElement.METHOD_PRIVATE); boolean useStaticMethod = hasElement(ClassSignatureElement.METHOD_STATIC); for (Method method : clazz.getDeclaredMethods()) { if (!usePrivateMethod && Modifier.isPrivate(method.getModifiers())) continue; if (!useStaticMethod && Modifier.isStatic(method.getModifiers())) continue; strings.add(getMethodString(method)); } } if (hasElement(ClassSignatureElement.CONSTRUCTOR)) { boolean usePrivateConstructor = hasElement(ClassSignatureElement.CONSTRUCTOR_PRIVATE); for (Constructor<?> method : clazz.getDeclaredConstructors()) { if (!usePrivateConstructor && Modifier.isPrivate(method.getModifiers())) continue; strings.add(getConstructorString(method)); } } if (hasElement(ClassSignatureElement.CLASS_ANNOTATION)) { strings.add(annotationToString(clazz.getAnnotations())); } if (hasElement(ClassSignatureElement.INTERFACES)) { for (Class<?> iClass : clazz.getInterfaces()) { strings.add(iClass.getName()); } } if (hasElement(ClassSignatureElement.SUPER_CLASS)) { if (clazz.getSuperclass() != null && !clazz.getSuperclass().getName().equals(Object.class.getName())) strings.add(clazz.getSuperclass().getName()); } if (hasElement(ClassSignatureElement.FIELD)) { boolean useStaticField = hasElement(ClassSignatureElement.FIELD_STATIC); boolean useFieldAnnotation = hasElement(ClassSignatureElement.FIELD_ANNOTATION); for (Field field : clazz.getDeclaredFields()) { if (!useStaticField && Modifier.isStatic(field.getModifiers())) continue; String fieldSignature = field.getType().getName() + " " + field.getName(); if (useFieldAnnotation) { fieldSignature += annotationToString(field.getAnnotations()); } strings.add(fieldSignature + ";"); } } Collections.sort(strings); StringBuilder strBuilder = new StringBuilder(); for (String methodString : strings) { strBuilder.append(methodString); } return strBuilder.toString(); } private String getConstructorString(Constructor<?> method) { StringBuilder strBuilder = new StringBuilder(); strBuilder.append(Modifier.toString(method.getModifiers()) + " "); strBuilder.append(method.getName()); strBuilder.append(getParams(method.getParameterTypes())); if (hasElement(ClassSignatureElement.METHOD_ANNOTATION)) strBuilder.append(annotationToString(method.getDeclaredAnnotations())); if (hasElement(ClassSignatureElement.METHOD_PARAM_ANNOTATION)) strBuilder.append(annotationToString(method.getParameterAnnotations())); if (hasElement(ClassSignatureElement.METHOD_EXCEPTION)) strBuilder.append(Arrays.toString(sort(method.getExceptionTypes()))); strBuilder.append(";"); return strBuilder.toString(); } private String getMethodString(Method method) { StringBuilder strBuilder = new StringBuilder(); strBuilder.append(Modifier.toString(method.getModifiers()) + " "); strBuilder.append(getName(method.getReturnType()) + " " + method.getName()); strBuilder.append(getParams(method.getParameterTypes())); if (hasElement(ClassSignatureElement.METHOD_ANNOTATION)) strBuilder.append(annotationToString(method.getDeclaredAnnotations())); if (hasElement(ClassSignatureElement.METHOD_PARAM_ANNOTATION)) strBuilder.append(annotationToString(method.getParameterAnnotations())); if (hasElement(ClassSignatureElement.METHOD_EXCEPTION)) strBuilder.append(Arrays.toString(sort(method.getExceptionTypes()))); strBuilder.append(";"); return strBuilder.toString(); } private <T> T[] sort(T[] a) { a = Arrays.copyOf(a, a.length); Arrays.sort(a, ToStringComparator.INSTANCE); return a; } private String getParams(Class<?>[] parameterTypes) { StringBuilder strB = new StringBuilder("("); boolean first = true; for (Class<?> ctClass : parameterTypes) { if (!first) strB.append(","); else first = false; strB.append(getName(ctClass)); } strB.append(")"); return strB.toString(); } private String getName(Class<?> ctClass) { if (ctClass.isArray()) return Descriptor.toString(ctClass.getName()); else return ctClass.getName(); } }