package org.hotswap.agent.util.signature; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.List; import org.hotswap.agent.javassist.CtClass; import org.hotswap.agent.javassist.CtConstructor; import org.hotswap.agent.javassist.CtField; import org.hotswap.agent.javassist.CtMethod; import org.hotswap.agent.javassist.NotFoundException; /** * CtClassSignature. Creates signature for given ctClass * * @author Erki Ehtla, Vladimir Dvorak */ public class CtClassSignature extends ClassSignatureBase { private CtClass ctClass; /** * @param ctClass the class for signature is to be counted */ public CtClassSignature(CtClass ctClass) { this.ctClass = ctClass; } @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 (CtMethod method : ctClass.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 (CtConstructor method : ctClass.getDeclaredConstructors()) { if (!usePrivateConstructor && Modifier.isPrivate(method.getModifiers())) continue; strings.add(getConstructorString(method)); } } if (hasElement(ClassSignatureElement.CLASS_ANNOTATION)) { strings.add(annotationToString(ctClass.getAvailableAnnotations())); } if (hasElement(ClassSignatureElement.INTERFACES)) { for (CtClass iClass : ctClass.getInterfaces()) { strings.add(iClass.getName()); } } if (hasElement(ClassSignatureElement.SUPER_CLASS)) { if (ctClass.getSuperclass() != null && !ctClass.getSuperclass().getName().equals(Object.class.getName())) strings.add(ctClass.getSuperclass().getName()); } if (hasElement(ClassSignatureElement.FIELD)) { boolean useStaticField = hasElement(ClassSignatureElement.FIELD_STATIC); boolean useFieldAnnotation = hasElement(ClassSignatureElement.FIELD_ANNOTATION); for (CtField field : ctClass.getDeclaredFields()) { if (!useStaticField && Modifier.isStatic(field.getModifiers())) continue; String fieldSignature = field.getType().getName() + " " + field.getName(); if (useFieldAnnotation) { fieldSignature += annotationToString(field.getAvailableAnnotations()); } strings.add(fieldSignature + ";"); } } Collections.sort(strings); StringBuilder strBuilder = new StringBuilder(); for (String methodString : strings) { strBuilder.append(methodString); } return strBuilder.toString(); } private String getName(CtClass ctClass) { return ctClass.getName(); } private String getConstructorString(CtConstructor method) throws ClassNotFoundException, NotFoundException { StringBuilder strBuilder = new StringBuilder(); strBuilder.append(Modifier.toString(method.getModifiers()) + " "); strBuilder.append(method.getDeclaringClass().getName()); strBuilder.append(getParams(method.getParameterTypes())); if (hasElement(ClassSignatureElement.METHOD_ANNOTATION)) strBuilder.append(annotationToString(method.getAvailableAnnotations())); if (hasElement(ClassSignatureElement.METHOD_PARAM_ANNOTATION)) strBuilder.append(annotationToString(method.getAvailableParameterAnnotations())); if (hasElement(ClassSignatureElement.METHOD_EXCEPTION)) strBuilder.append(toStringException(method.getExceptionTypes())); strBuilder.append(";"); return strBuilder.toString(); } private String getMethodString(CtMethod method) throws NotFoundException, ClassNotFoundException { 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.getAvailableAnnotations())); if (hasElement(ClassSignatureElement.METHOD_PARAM_ANNOTATION)) strBuilder.append(annotationToString(method.getAvailableParameterAnnotations())); if (hasElement(ClassSignatureElement.METHOD_EXCEPTION)) strBuilder.append(toStringException(method.getExceptionTypes())); strBuilder.append(";"); return strBuilder.toString(); } private String getParams(CtClass[] ctClasses) { StringBuilder strBuilder = new StringBuilder("("); boolean first = true; for (CtClass ctClass : ctClasses) { if (!first) strBuilder.append(","); else first = false; strBuilder.append(getName(ctClass)); } strBuilder.append(")"); return strBuilder.toString(); } private String toStringException(CtClass[] a) { if (a == null) return "null"; int iMax = a.length - 1; if (iMax == -1) return "[]"; a = sort(a); StringBuilder b = new StringBuilder(); b.append('['); for (int i = 0;; i++) { b.append("class " + a[i].getName()); if (i == iMax) return b.append(']').toString(); b.append(", "); } } private CtClass[] sort(CtClass[] a) { a = Arrays.copyOf(a, a.length); Arrays.sort(a, CtClassComparator.INSTANCE); return a; } private static class CtClassComparator implements Comparator<CtClass> { public static final CtClassComparator INSTANCE = new CtClassComparator(); @Override public int compare(CtClass o1, CtClass o2) { return o1.getName().compareTo(o2.getName()); } } }