public static CtClass makeInvocationClassNoCtors( AOPClassPool pool, boolean makeInnerClass, CtClass outerClass, String className, CtClass superInvocation) throws CannotCompileException, NotFoundException { CtClass untransformable = pool.get("org.jboss.aop.instrument.Untransformable"); CtClass invocation; if (makeInnerClass) { // Strip away the package from classname String innerClassName = className.substring(className.lastIndexOf('.') + 1); defrostClassIfExists(pool, outerClass.getName() + "$" + innerClassName); // Only static nested classes are supported boolean classStatic = true; invocation = TransformerCommon.makeNestedClass(outerClass, innerClassName, classStatic); invocation.setSuperclass(superInvocation); } else { defrostClassIfExists(pool, className); invocation = TransformerCommon.makeClass(pool, className, superInvocation); } invocation.addInterface(untransformable); return invocation; }
private static TemplateRenderer tryToCompile(String source, Map<String, String> expressions) throws NotFoundException, CannotCompileException, InstantiationException, IllegalAccessException { ClassPool cp = ClassPool.getDefault(); CtClass sup = cp.get(Object.class.getCanonicalName()); CtClass cls = cp.makeClass("RapidoidTemplate" + ID_GEN.incrementAndGet(), sup); cls.addInterface(cp.get(TemplateRenderer.class.getCanonicalName())); cls.addConstructor(CtNewConstructor.defaultConstructor(cls)); for (Map.Entry<String, String> expr : expressions.entrySet()) { String fld = "private static final org.rapidoid.render.retriever.ValueRetriever %s = org.rapidoid.render.retriever.Retriever.of(%s);"; String retrieverId = retrieverId(expr.getKey()); String prop = expr.getValue(); String field = U.frmt(fld, retrieverId, prop); cls.addField(CtField.make(field, cls)); } CtClass[] params = {cp.get(RenderCtx.class.getCanonicalName())}; CtClass clsVoid = cp.get(void.class.getCanonicalName()); cls.addMethod( CtNewMethod.make(Modifier.PUBLIC, clsVoid, "render", params, new CtClass[0], source, cls)); return (TemplateRenderer) cls.toClass().newInstance(); }
public static Getter generateGetter(OgnlContext context, String code) throws OgnlException { String className = NAME_FACTORY.getNewClassName(); try { ClassPool pool = (ClassPool) pools.get(context.getClassResolver()); EnhancedClassLoader loader = (EnhancedClassLoader) loaders.get(context.getClassResolver()); CtClass newClass; CtClass ognlContextClass; CtClass objectClass; CtClass stringClass; CtMethod method; byte[] byteCode; Class compiledClass; if ((pool == null) || (loader == null)) { ClassLoader classLoader = new ContextClassLoader(OgnlContext.class.getClassLoader(), context); pool = ClassPool.getDefault(); pool.insertClassPath(new LoaderClassPath(classLoader)); pools.put(context.getClassResolver(), pool); loader = new EnhancedClassLoader(classLoader); loaders.put(context.getClassResolver(), loader); } newClass = pool.makeClass(className); ognlContextClass = pool.get(OgnlContext.class.getName()); objectClass = pool.get(Object.class.getName()); stringClass = pool.get(String.class.getName()); newClass.addInterface(pool.get(Getter.class.getName())); method = new CtMethod( objectClass, "get", new CtClass[] {ognlContextClass, objectClass, stringClass}, newClass); method.setBody("{" + code + "}"); newClass.addMethod(method); byteCode = newClass.toBytecode(); compiledClass = loader.defineClass(className, byteCode); return (Getter) compiledClass.newInstance(); } catch (Throwable ex) { throw new OgnlException("Cannot create class", ex); } }
public void onWrite(ClassPool pool, String className) throws NotFoundException, CannotCompileException { CtClass cc = pool.get(className); try { if (isPersistent(className)) { CtClass base = cc.getSuperclass(); CtConstructor cons = new CtConstructor(constructorParams, cc); if (base.subclassOf(persistent) || base == object) { cons.setBody(null); cc.addConstructor(cons); if (base == object) { cc.setSuperclass(persistent); } } else { if (!isPersistent(base.getName())) { throw new NotFoundException( "Base class " + base.getName() + " was not declared as persistent"); } cons.setBody("super($0);"); cc.addConstructor(cons); } preprocessMethods(cc, true, true); if (base == persistent || base == object) { CtMethod m = new CtMethod(isRecursive, cc, null); m.setBody("return false;"); cc.addMethod(m); addSerializeMethods(cc, false); } else if (base.subtypeOf(serializable)) { addSerializeMethods(cc, true); } if ((cc.getModifiers() & Modifier.PRIVATE) == 0) { CtClass f = pool.makeClass(className + "LoadFactory"); f.addInterface(factory); CtMethod c = new CtMethod(create, f, null); c.setBody("return new " + className + "($1);"); f.addMethod(c); CtNewConstructor.defaultConstructor(f); } } else { preprocessMethods( cc, cc.subtypeOf(persistent) && cc != persistent, !className.startsWith("org.nachodb")); } } catch (Exception x) { x.printStackTrace(); } }
private void handleCompositeField( CtClass managedCtClass, CtField persistentField, CtMethod fieldWriter) throws NotFoundException, CannotCompileException { if (!persistentField.hasAnnotation(Embedded.class)) { return; } // make sure to add the CompositeOwner interface managedCtClass.addInterface(classPool.get(CompositeOwner.class.getName())); if (enhancementContext.isCompositeClass(managedCtClass)) { // if a composite have a embedded field we need to implement the TRACKER_CHANGER_NAME method // as well MethodWriter.write( managedCtClass, "" + "public void %1$s(String name) {%n" + " if (%2$s != null) { %2$s.callOwner(\".\" + name) ; }%n}", EnhancerConstants.TRACKER_CHANGER_NAME, EnhancerConstants.TRACKER_COMPOSITE_FIELD_NAME); } // cleanup previous owner fieldWriter.insertBefore( String.format( "" + "if (%1$s != null) { ((%2$s) %1$s).%3$s(\"%1$s\"); }%n", persistentField.getName(), CompositeTracker.class.getName(), EnhancerConstants.TRACKER_COMPOSITE_CLEAR_OWNER)); // trigger track changes fieldWriter.insertAfter( String.format( "" + "((%2$s) %1$s).%4$s(\"%1$s\", (%3$s) this);%n" + "%5$s(\"%1$s\");", persistentField.getName(), CompositeTracker.class.getName(), CompositeOwner.class.getName(), EnhancerConstants.TRACKER_COMPOSITE_SET_OWNER, EnhancerConstants.TRACKER_CHANGER_NAME)); }
@Override public byte[] transform( ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { // Be careful with Apache library usage in this class (e.g. ArrayUtils). Usage will likely cause // a ClassCircularityError // under JRebel. Favor not including outside libraries and unnecessary classes. CtClass clazz = null; try { boolean mySkipOverlaps = skipOverlaps; boolean myRenameMethodOverlaps = renameMethodOverlaps; String convertedClassName = className.replace('/', '.'); ClassPool classPool = null; String xformKey = convertedClassName; String[] xformVals = null; Boolean[] xformSkipOverlaps = null; Boolean[] xformRenameMethodOverlaps = null; if (!xformTemplates.isEmpty()) { if (xformTemplates.containsKey(xformKey)) { xformVals = xformTemplates.get(xformKey).split(","); classPool = ClassPool.getDefault(); clazz = classPool.makeClass(new ByteArrayInputStream(classfileBuffer), false); } } else { if (annotationTransformedClasses.contains(convertedClassName)) { logger.warn( convertedClassName + " has already been transformed by a previous instance of DirectCopyTransfomer. " + "Skipping this annotation based transformation. Generally, annotation-based transformation is handled " + "by bean id blAnnotationDirectCopyClassTransformer with template tokens being added to " + "blDirectCopyTransformTokenMap via EarlyStageMergeBeanPostProcessor."); } boolean isValidPattern = true; List<DirectCopyIgnorePattern> matchedPatterns = new ArrayList<DirectCopyIgnorePattern>(); for (DirectCopyIgnorePattern pattern : ignorePatterns) { boolean isPatternMatch = false; for (String patternString : pattern.getPatterns()) { isPatternMatch = convertedClassName.matches(patternString); if (isPatternMatch) { break; } } if (isPatternMatch) { matchedPatterns.add(pattern); } isValidPattern = !(isPatternMatch && pattern.getTemplateTokenPatterns() == null); if (!isValidPattern) { return null; } } if (isValidPattern) { classPool = ClassPool.getDefault(); clazz = classPool.makeClass(new ByteArrayInputStream(classfileBuffer), false); List<?> attributes = clazz.getClassFile().getAttributes(); Iterator<?> itr = attributes.iterator(); List<String> templates = new ArrayList<String>(); List<Boolean> skips = new ArrayList<Boolean>(); List<Boolean> renames = new ArrayList<Boolean>(); check: { while (itr.hasNext()) { Object object = itr.next(); if (AnnotationsAttribute.class.isAssignableFrom(object.getClass())) { AnnotationsAttribute attr = (AnnotationsAttribute) object; Annotation[] items = attr.getAnnotations(); for (Annotation annotation : items) { String typeName = annotation.getTypeName(); if (typeName.equals(DirectCopyTransform.class.getName())) { ArrayMemberValue arrayMember = (ArrayMemberValue) annotation.getMemberValue("value"); for (MemberValue arrayMemberValue : arrayMember.getValue()) { AnnotationMemberValue member = (AnnotationMemberValue) arrayMemberValue; Annotation memberAnnot = member.getValue(); ArrayMemberValue annot = (ArrayMemberValue) memberAnnot.getMemberValue("templateTokens"); for (MemberValue memberValue : annot.getValue()) { String val = ((StringMemberValue) memberValue).getValue(); if (val != null && templateTokens.containsKey(val)) { templateCheck: { for (DirectCopyIgnorePattern matchedPattern : matchedPatterns) { for (String ignoreToken : matchedPattern.getTemplateTokenPatterns()) { if (val.matches(ignoreToken)) { break templateCheck; } } } templates.add(templateTokens.get(val)); } } } BooleanMemberValue skipAnnot = (BooleanMemberValue) memberAnnot.getMemberValue("skipOverlaps"); if (skipAnnot != null) { skips.add(skipAnnot.getValue()); } else { skips.add(mySkipOverlaps); } BooleanMemberValue renameAnnot = (BooleanMemberValue) memberAnnot.getMemberValue("renameMethodOverlaps"); if (renameAnnot != null) { renames.add(renameAnnot.getValue()); } else { renames.add(myRenameMethodOverlaps); } } xformVals = templates.toArray(new String[templates.size()]); xformSkipOverlaps = skips.toArray(new Boolean[skips.size()]); xformRenameMethodOverlaps = renames.toArray(new Boolean[renames.size()]); break check; } } } } } } } if (xformVals != null && xformVals.length > 0) { logger.lifecycle( LifeCycleEvent.START, String.format( "Transform - Copying into [%s] from [%s]", xformKey, StringUtils.join(xformVals, ","))); // Load the destination class and defrost it so it is eligible for modifications clazz.defrost(); int index = 0; for (String xformVal : xformVals) { // Load the source class String trimmed = xformVal.trim(); classPool.appendClassPath(new LoaderClassPath(Class.forName(trimmed).getClassLoader())); CtClass template = classPool.get(trimmed); // Add in extra interfaces CtClass[] interfacesToCopy = template.getInterfaces(); for (CtClass i : interfacesToCopy) { checkInterfaces: { CtClass[] myInterfaces = clazz.getInterfaces(); for (CtClass myInterface : myInterfaces) { if (myInterface.getName().equals(i.getName())) { if (xformSkipOverlaps[index]) { break checkInterfaces; } else { throw new RuntimeException( "Duplicate interface detected " + myInterface.getName()); } } } logger.debug(String.format("Adding interface [%s]", i.getName())); clazz.addInterface(i); } } // copy over any EntityListeners ClassFile classFile = clazz.getClassFile(); ClassFile templateFile = template.getClassFile(); ConstPool constantPool = classFile.getConstPool(); buildClassLevelAnnotations(classFile, templateFile, constantPool); // Copy over all declared fields from the template class // Note that we do not copy over fields with the @NonCopiedField annotation CtField[] fieldsToCopy = template.getDeclaredFields(); for (CtField field : fieldsToCopy) { if (field.hasAnnotation(NonCopied.class)) { logger.debug(String.format("Not adding field [%s]", field.getName())); } else { try { CtField ctField = clazz.getDeclaredField(field.getName()); String originalSignature = ctField.getSignature(); String mySignature = field.getSignature(); if (!originalSignature.equals(mySignature)) { throw new IllegalArgumentException( "Field with name (" + field.getName() + ") and signature " + "(" + field.getSignature() + ") is targeted for weaving into (" + clazz.getName() + "). " + "An incompatible field of the same name and signature of (" + ctField.getSignature() + ") " + "already exists. The field in the target class should be updated to a different name, " + "or made to have a matching type."); } if (xformSkipOverlaps[index]) { logger.debug(String.format("Skipping overlapped field [%s]", field.getName())); continue; } } catch (NotFoundException e) { // do nothing -- field does not exist } logger.debug(String.format("Adding field [%s]", field.getName())); CtField copiedField = new CtField(field, clazz); boolean defaultConstructorFound = false; String implClass = getImplementationType(field.getType().getName()); // Look through all of the constructors in the implClass to see // if there is one that takes zero parameters try { CtConstructor[] implConstructors = classPool.get(implClass).getConstructors(); if (implConstructors != null) { for (CtConstructor cons : implConstructors) { if (cons.getParameterTypes().length == 0) { defaultConstructorFound = true; break; } } } } catch (NotFoundException e) { // Do nothing -- if we don't find this implementation, it's probably because it's // an array. In this case, we will not initialize the field. } if (defaultConstructorFound) { clazz.addField(copiedField, "new " + implClass + "()"); } else { clazz.addField(copiedField); } } } // Copy over all declared methods from the template class CtMethod[] methodsToCopy = template.getDeclaredMethods(); for (CtMethod method : methodsToCopy) { if (method.hasAnnotation(NonCopied.class)) { logger.debug(String.format("Not adding method [%s]", method.getName())); } else { try { CtClass[] paramTypes = method.getParameterTypes(); CtMethod originalMethod = clazz.getDeclaredMethod(method.getName(), paramTypes); if (xformSkipOverlaps[index]) { logger.debug( String.format( "Skipping overlapped method [%s]", methodDescription(originalMethod))); continue; } if (transformedMethods.contains(methodDescription(originalMethod))) { throw new RuntimeException( "Method already replaced " + methodDescription(originalMethod)); } else { logger.debug( String.format("Marking as replaced [%s]", methodDescription(originalMethod))); transformedMethods.add(methodDescription(originalMethod)); } logger.debug(String.format("Removing method [%s]", method.getName())); if (xformRenameMethodOverlaps[index]) { originalMethod.setName(renameMethodPrefix + method.getName()); } else { clazz.removeMethod(originalMethod); } } catch (NotFoundException e) { // Do nothing -- we don't need to remove a method because it doesn't exist } logger.debug(String.format("Adding method [%s]", method.getName())); CtMethod copiedMethod = new CtMethod(method, clazz, null); clazz.addMethod(copiedMethod); } } index++; } if (xformTemplates.isEmpty()) { annotationTransformedClasses.add(convertedClassName); } logger.lifecycle( LifeCycleEvent.END, String.format( "Transform - Copying into [%s] from [%s]", xformKey, StringUtils.join(xformVals, ","))); return clazz.toBytecode(); } } catch (ClassCircularityError error) { error.printStackTrace(); throw error; } catch (Exception e) { throw new RuntimeException("Unable to transform class", e); } finally { if (clazz != null) { clazz.detach(); } } return null; }
@Override public byte[] transform( ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { String convertedClassName = className.replace('/', '.'); if (xformTemplates.containsKey(convertedClassName)) { String xformKey = convertedClassName; String[] xformVals = xformTemplates.get(xformKey).split(","); logger.lifecycle( LifeCycleEvent.START, String.format( "Transform - Copying into [%s] from [%s]", xformKey, StringUtils.join(xformVals, ","))); try { // Load the destination class and defrost it so it is eligible for modifications ClassPool classPool = ClassPool.getDefault(); CtClass clazz = classPool.makeClass(new ByteArrayInputStream(classfileBuffer), false); clazz.defrost(); for (String xformVal : xformVals) { // Load the source class String trimmed = xformVal.trim(); classPool.appendClassPath(new LoaderClassPath(Class.forName(trimmed).getClassLoader())); CtClass template = classPool.get(trimmed); // Add in extra interfaces CtClass[] interfacesToCopy = template.getInterfaces(); for (CtClass i : interfacesToCopy) { logger.debug(String.format("Adding interface [%s]", i.getName())); clazz.addInterface(i); } // Copy over all declared fields from the template class // Note that we do not copy over fields with the @NonCopiedField annotation CtField[] fieldsToCopy = template.getDeclaredFields(); for (CtField field : fieldsToCopy) { if (field.hasAnnotation(NonCopied.class)) { logger.debug(String.format("Not adding field [%s]", field.getName())); } else { logger.debug(String.format("Adding field [%s]", field.getName())); CtField copiedField = new CtField(field, clazz); boolean defaultConstructorFound = false; String implClass = getImplementationType(field.getType().getName()); // Look through all of the constructors in the implClass to see // if there is one that takes zero parameters try { CtConstructor[] implConstructors = classPool.get(implClass).getConstructors(); if (implConstructors != null) { for (CtConstructor cons : implConstructors) { if (cons.getParameterTypes().length == 0) { defaultConstructorFound = true; break; } } } } catch (NotFoundException e) { // Do nothing -- if we don't find this implementation, it's probably because it's // an array. In this case, we will not initialize the field. } if (defaultConstructorFound) { clazz.addField(copiedField, "new " + implClass + "()"); } else { clazz.addField(copiedField); } } } // Copy over all declared methods from the template class CtMethod[] methodsToCopy = template.getDeclaredMethods(); for (CtMethod method : methodsToCopy) { if (method.hasAnnotation(NonCopied.class)) { logger.debug(String.format("Not adding method [%s]", method.getName())); } else { try { CtClass[] paramTypes = method.getParameterTypes(); CtMethod originalMethod = clazz.getDeclaredMethod(method.getName(), paramTypes); if (transformedMethods.contains(methodDescription(originalMethod))) { throw new RuntimeException( "Method already replaced " + methodDescription(originalMethod)); } else { logger.debug( String.format("Marking as replaced [%s]", methodDescription(originalMethod))); transformedMethods.add(methodDescription(originalMethod)); } logger.debug(String.format("Removing method [%s]", method.getName())); clazz.removeMethod(originalMethod); } catch (NotFoundException e) { // Do nothing -- we don't need to remove a method because it doesn't exist } logger.debug(String.format("Adding method [%s]", method.getName())); CtMethod copiedMethod = new CtMethod(method, clazz, null); clazz.addMethod(copiedMethod); } } } logger.lifecycle( LifeCycleEvent.END, String.format( "Transform - Copying into [%s] from [%s]", xformKey, StringUtils.join(xformVals, ","))); return clazz.toBytecode(); } catch (Exception e) { throw new RuntimeException("Unable to transform class", e); } } return null; }
private boolean addSerializeMethods(CtClass cc, boolean callSuper) throws NotFoundException, CannotCompileException { CtField[] fields = cc.getDeclaredFields(); int size = 0; StringBuffer sb = new StringBuffer(); sb.append(callSuper ? "{$2=super.pack($1, $2);$1.extend($2" : "{$1.extend($2"); for (int i = 0; i < fields.length; i++) { CtField f = fields[i]; if ((f.getModifiers() & (Modifier.STATIC | Modifier.TRANSIENT)) == 0) { CtClass type = f.getType(); if (type.isPrimitive()) { if (type == CtClass.booleanType || type == CtClass.byteType) { size += 1; } else if (type == CtClass.charType || type == CtClass.shortType) { size += 2; } else if (type == CtClass.longType || type == CtClass.doubleType) { size += 8; } else { size += 4; } } else if (type.getName().equals("java.lang.String")) { sb.append("+org.nachodb.impl.Bytes#sizeof("); sb.append(f.getName()); sb.append(",$3)"); } else { return false; } } } cc.addInterface(serializable); CtMethod m = new CtMethod(pack, cc, null); sb.append('+'); sb.append(size); sb.append(");"); for (int i = 0; i < fields.length; i++) { CtField f = fields[i]; if ((f.getModifiers() & (Modifier.STATIC | Modifier.TRANSIENT)) == 0) { CtClass type = f.getType(); String name = f.getName(); if (type == CtClass.booleanType) { sb.append("$1.arr[$2++]=(byte)("); sb.append(name); sb.append("?1:0);"); } else if (type == CtClass.charType) { sb.append("org.nachodb.impl.Bytes#pack2($1.arr,$2,(short)"); sb.append(name); sb.append(");$2+=2;"); } else if (type == CtClass.byteType) { sb.append("$1.arr[$2++]="); sb.append(name); sb.append(";"); } else if (type == CtClass.shortType) { sb.append("org.nachodb.impl.Bytes#pack2($1.arr,$2,"); sb.append(name); sb.append(");$2+=2;"); } else if (type == CtClass.intType) { sb.append("org.nachodb.impl.Bytes#pack4($1.arr,$2,"); sb.append(name); sb.append(");$2+=4;"); } else if (type == CtClass.longType) { sb.append("org.nachodb.impl.Bytes#pack8($1.arr,$2,"); sb.append(name); sb.append(");$2+=8;"); } else if (type == CtClass.doubleType) { sb.append("org.nachodb.impl.Bytes#packF8($1.arr,$2,"); sb.append(name); sb.append(");$2+=8;"); } else if (type == CtClass.floatType) { sb.append("org.nachodb.impl.Bytes#packF4($1.arr,$2,"); sb.append(name); sb.append(");$2+=4;"); } else { sb.append("$2=org.nachodb.impl.Bytes#packStr($1.arr,$2,"); sb.append(name); sb.append(",$3);"); } } } sb.append("return $2;}"); m.setBody(sb.toString()); cc.addMethod(m); m = new CtMethod(unpack, cc, null); sb = new StringBuffer(); sb.append(callSuper ? "{$2=super.unpack($1, $2);" : "{"); for (int i = 0; i < fields.length; i++) { CtField f = fields[i]; if ((f.getModifiers() & (Modifier.STATIC | Modifier.TRANSIENT)) == 0) { CtClass type = f.getType(); String name = f.getName(); sb.append(name); sb.append('='); if (type == CtClass.booleanType) { sb.append("$1[$2++]!=0;"); } else if (type == CtClass.charType) { sb.append("(char)org.nachodb.impl.Bytes#unpack2($1,$2);$2+=2;"); } else if (type == CtClass.byteType) { sb.append("$1[$2++];"); } else if (type == CtClass.shortType) { sb.append("org.nachodb.impl.Bytes#unpack2($1,$2);$2+=2;"); } else if (type == CtClass.intType) { sb.append("org.nachodb.impl.Bytes#unpack4($1,$2);$2+=4;"); } else if (type == CtClass.longType) { sb.append("org.nachodb.impl.Bytes#unpack8($1,$2);$2+=8;"); } else if (type == CtClass.doubleType) { sb.append("org.nachodb.impl.Bytes#unpackF8($1,$2);$2+=8;"); } else if (type == CtClass.floatType) { sb.append("org.nachodb.impl.Bytes#unpackF4($1,$2);$2+=4;"); } else { sb.append( "org.nachodb.impl.Bytes#unpackStr($1,$2,$3);$2+=org.nachodb.impl.Bytes#sizeof($1,$2);"); } } } sb.append("return $2;}"); m.setBody(sb.toString()); cc.addMethod(m); return true; }
public byte[] injectReactive(String classname) throws Exception { init(); CtClass droolsPojo = cp.get(classname); if (collectReactiveFields(droolsPojo).size() == 0) { LOG.info( "Skipped bytecode injection in class " + droolsPojo.getName() + " because no fields candidated for reactivity."); return droolsPojo.toBytecode(); } droolsPojo.addInterface(cp.get(ReactiveObject.class.getName())); CtField ltsCtField = new CtField(cp.get(Collection.class.getName()), DROOLS_LIST_OF_TUPLES, droolsPojo); ltsCtField.setModifiers(Modifier.PRIVATE); ClassType listOfTuple = new SignatureAttribute.ClassType( Collection.class.getName(), new TypeArgument[] { new TypeArgument(new SignatureAttribute.ClassType(Tuple.class.getName())) }); ltsCtField.setGenericSignature(listOfTuple.encode()); // Do not use the Initializer.byNew... as those method always pass at least 1 parameter which is // "this". droolsPojo.addField(ltsCtField, Initializer.byExpr("new java.util.HashSet();")); final CtMethod getLeftTuplesCtMethod = CtNewMethod.make( "public java.util.Collection getLeftTuples() {\n" + " return this.$$_drools_lts != null ? this.$$_drools_lts : java.util.Collections.emptyList();\n" + "}", droolsPojo); MethodSignature getLeftTuplesSignature = new MethodSignature(null, null, listOfTuple, null); getLeftTuplesCtMethod.setGenericSignature(getLeftTuplesSignature.encode()); droolsPojo.addMethod(getLeftTuplesCtMethod); final CtMethod addLeftTupleCtMethod = CtNewMethod.make( "public void addLeftTuple(" + Tuple.class.getName() + " leftTuple) {\n" + " if ($$_drools_lts == null) {\n" + " $$_drools_lts = new java.util.HashSet();\n" + " }\n" + " $$_drools_lts.add(leftTuple);\n" + "}", droolsPojo); droolsPojo.addMethod(addLeftTupleCtMethod); final CtMethod removeLeftTupleCtMethod = CtNewMethod.make( "public void removeLeftTuple(" + Tuple.class.getName() + " leftTuple) {\n" + " $$_drools_lts.remove(leftTuple);\n" + "}", droolsPojo); droolsPojo.addMethod(removeLeftTupleCtMethod); Map<String, CtField> fieldsMap = collectReactiveFields(droolsPojo); for (CtField f : fieldsMap.values()) { LOG.debug("Preparing field writer method for field: {}.", f); writeMethods.put(f.getName(), makeWriter(droolsPojo, f)); } enhanceAttributesAccess(fieldsMap, droolsPojo); // first call CtClass.toClass() before the original class is loaded, it will persist the // bytecode instrumentation changes in the classloader. return droolsPojo.toBytecode(); }
/** * Given a bean-style interface, generate an instance of the interface by implementing getters and * setters for each property. It will also add implementations to support the {@link * SupportsRdfId} interface and generate simple, default equals, toString and hashCode methods. * * <p>If there are other non-bean style (getter and/or setter's for properties) methods on the * interface, this will likely fail to generate the instance. * * @param theInterface the interface to build an instance of * @param <T> the type of the interface * @return New dynamically generated bytecode of a class that implements the given interface. * @throws Exception if there is an error while generating the bytecode of the new class. */ public static synchronized <T> Class<T> generateInstanceClass(Class<T> theInterface) throws Exception { processedMethods.clear(); // TODO: can we use some sort of template language for this? ClassPool aPool = ClassPool.getDefault(); aPool.appendClassPath(new LoaderClassPath(theInterface.getClassLoader())); CtClass aInterface = aPool.get(theInterface.getName()); CtClass aSupportsRdfIdInterface = aPool.get(SupportsRdfId.class.getName()); CtClass aEmpireGeneratedInterface = aPool.get(EmpireGenerated.class.getName()); if (!Arrays.asList(aInterface.getInterfaces()).contains(aSupportsRdfIdInterface) && !SupportsRdfId.class.isAssignableFrom(theInterface)) { throw new IllegalArgumentException( "Class '" + theInterface.getName() + "' does not implement SupportsRdfId, cannot generate Empire suitable implementation."); } String aName = aInterface.getPackageName() + ".impl." + aInterface.getSimpleName() + "Impl"; CtClass aClass = null; try { // i had a good reason for doing this, but i dont remember what it is. when i do, i'll // explain it here =) aClass = aPool.get(aName); return (Class<T>) BeanReflectUtil.loadClass(aName); } catch (NotFoundException e) { aClass = aPool.makeClass( aInterface.getPackageName() + ".impl." + aInterface.getSimpleName() + "Impl"); } catch (ClassNotFoundException e) { throw new Exception("Previously created class cannot be loaded.", e); } if (aClass.isFrozen()) { aClass.defrost(); } if (aInterface.isInterface()) { aClass.addInterface(aInterface); } else { aClass.setSuperclass(aInterface); } aClass.addInterface(aSupportsRdfIdInterface); aClass.addInterface(aEmpireGeneratedInterface); CtField aInterfaceField = new CtField(aPool.get(Class.class.getName()), "mInterfaceClass", aClass); aClass.addField( aInterfaceField, CtField.Initializer.byExpr(theInterface.getName() + ".class;")); CtField aAllTriplesField = new CtField(aPool.get(Graph.class.getName()), "mAllTriples", aClass); aClass.addField( aAllTriplesField, CtField.Initializer.byExpr("new com.clarkparsia.openrdf.ExtGraph();")); CtField aInstanceTriplesField = new CtField(aPool.get(Graph.class.getName()), "mInstanceTriples", aClass); aClass.addField( aInstanceTriplesField, CtField.Initializer.byExpr("new com.clarkparsia.openrdf.ExtGraph();")); aClass.addConstructor(CtNewConstructor.defaultConstructor(aClass)); generateMethods(theInterface, aPool, aClass); generateMethodsForSuperInterfaces(theInterface, aPool, aClass); CtField aIdField = new CtField(aPool.get(SupportsRdfId.class.getName()), "supportsId", aClass); aClass.addField( aIdField, CtField.Initializer.byExpr("new com.clarkparsia.empire.annotation.SupportsRdfIdImpl();")); if (!hasMethod(aClass, "getRdfId")) { aClass.addMethod( CtNewMethod.make( "public com.clarkparsia.empire.SupportsRdfId.RdfKey getRdfId() { return supportsId.getRdfId(); } ", aClass)); } if (!hasMethod(aClass, "setRdfId")) { aClass.addMethod( CtNewMethod.make( "public void setRdfId(com.clarkparsia.empire.SupportsRdfId.RdfKey theURI) { supportsId.setRdfId(theURI); } ", aClass)); } if (!hasMethod(aClass, "getAllTriples")) { aClass.addMethod( CtNewMethod.make( "public org.openrdf.model.Graph getAllTriples() { return mAllTriples; } ", aClass)); } if (!hasMethod(aClass, "setAllTriples")) { aClass.addMethod( CtNewMethod.make( "public void setAllTriples(org.openrdf.model.Graph theGraph) { mAllTriples = theGraph; } ", aClass)); } if (!hasMethod(aClass, "getInstanceTriples")) { aClass.addMethod( CtNewMethod.make( "public org.openrdf.model.Graph getInstanceTriples() { return mInstanceTriples; } ", aClass)); } if (!hasMethod(aClass, "setInstanceTriples")) { aClass.addMethod( CtNewMethod.make( "public void setInstanceTriples(org.openrdf.model.Graph theGraph) { mInstanceTriples = theGraph; } ", aClass)); } String equalsMethodBody = "public boolean equals(Object theObj) {\n" + " if (theObj == this) return true;\n" + " if (!(theObj instanceof com.clarkparsia.empire.SupportsRdfId)) return false;\n" + " if (!(mInterfaceClass.isAssignableFrom(theObj.getClass()))) return false;\n" + " return getRdfId().equals( ((com.clarkparsia.empire.SupportsRdfId) theObj).getRdfId()) && super.equals(theObj);\n" + "}\n"; aClass.addMethod(CtNewMethod.make(equalsMethodBody, aClass)); if (theInterface.isInterface()) { aClass.addMethod( CtNewMethod.make( "public String toString() { return getRdfId() != null ? getRdfId().toString() : super.toString(); } ", aClass)); aClass.addMethod( CtNewMethod.make( "public int hashCode() { return getRdfId() != null ? getRdfId().hashCode() : 0; } ", aClass)); } aClass.freeze(); Class<T> aResult = (Class<T>) aClass.toClass(); try { // make sure this is a valid class, that is, we can create instances of it! aResult.newInstance(); } catch (Exception ex) { // TODO: log this? throw ex; } return aResult; }
/** Generate Javassist Proxy Classes */ private static <T> void generateProxyClass( Class<T> primaryInterface, String superClassName, String methodBody) throws Exception { String newClassName = superClassName.replaceAll("(.+)\\.(\\w+)", "$1.Hikari$2"); CtClass superCt = classPool.getCtClass(superClassName); CtClass targetCt = classPool.makeClass(newClassName, superCt); targetCt.setModifiers(Modifier.FINAL); System.out.println("Generating " + newClassName); targetCt.setModifiers(Modifier.PUBLIC); // Make a set of method signatures we inherit implementation for, so we don't generate delegates // for these Set<String> superSigs = new HashSet<>(); for (CtMethod method : superCt.getMethods()) { if ((method.getModifiers() & Modifier.FINAL) == Modifier.FINAL) { superSigs.add(method.getName() + method.getSignature()); } } Set<String> methods = new HashSet<>(); Set<Class<?>> interfaces = getAllInterfaces(primaryInterface); for (Class<?> intf : interfaces) { CtClass intfCt = classPool.getCtClass(intf.getName()); targetCt.addInterface(intfCt); for (CtMethod intfMethod : intfCt.getDeclaredMethods()) { final String signature = intfMethod.getName() + intfMethod.getSignature(); // don't generate delegates for methods we override if (superSigs.contains(signature)) { continue; } // Ignore already added methods that come from other interfaces if (methods.contains(signature)) { continue; } // Ignore default methods (only for Jre8 or later) if (isDefaultMethod(intf, intfCt, intfMethod)) { continue; } // Track what methods we've added methods.add(signature); // Clone the method we want to inject into CtMethod method = CtNewMethod.copy(intfMethod, targetCt, null); String modifiedBody = methodBody; // If the super-Proxy has concrete methods (non-abstract), transform the call into a simple // super.method() call CtMethod superMethod = superCt.getMethod(intfMethod.getName(), intfMethod.getSignature()); if ((superMethod.getModifiers() & Modifier.ABSTRACT) != Modifier.ABSTRACT) { modifiedBody = modifiedBody.replace("((cast) ", ""); modifiedBody = modifiedBody.replace("delegate", "super"); modifiedBody = modifiedBody.replace("super)", "super"); } modifiedBody = modifiedBody.replace("cast", primaryInterface.getName()); // Generate a method that simply invokes the same method on the delegate if (isThrowsSqlException(intfMethod)) { modifiedBody = modifiedBody.replace("method", method.getName()); } else { modifiedBody = "{ return ((cast) delegate).method($$); }" .replace("method", method.getName()) .replace("cast", primaryInterface.getName()); } if (method.getReturnType() == CtClass.voidType) { modifiedBody = modifiedBody.replace("return", ""); } method.setBody(modifiedBody); targetCt.addMethod(method); } } targetCt.writeFile("target/classes"); }
// 用javassit得到动态代理 public T createJavassistBytecodeDynamicProxy( LoadBalancer loadBalance, ConcurrentMap<String, T> map, Class ifaces) { try { ClassPool mPool = new ClassPool(true); CtClass mCtc = mPool.makeClass(ifaces.getName() + "JavaassistProxy"); mCtc.addInterface(mPool.get(ifaces.getName())); mCtc.addConstructor(CtNewConstructor.defaultConstructor(mCtc)); mCtc.addField(CtField.make("public " + loadBalance.getClass().getName() + " sub;", mCtc)); mCtc.addField(CtField.make("public " + map.getClass().getName() + " map;", mCtc)); // mCtc.addField(CtField.make("public " + ArrayList.class.getName() + " list;", // mCtc)); mCtc.addMethod( CtNewMethod.make( "public Object getRealClient() { return (Object)sub.select(new " + ArrayList.class.getName() + "(map.values())); }", mCtc)); // 获取接口的方法 for (Method method : ifaces.getMethods()) { Class returnType = method.getReturnType(); String modifiers = "public"; if (Modifier.PUBLIC == method.getModifiers()) { modifiers = "public"; } else if (Modifier.PROTECTED == method.getModifiers()) { modifiers = "protected"; } else if (Modifier.PRIVATE == method.getModifiers()) { modifiers = "private"; } Class<?>[] parameter = method.getParameterTypes(); String params = ""; String ps = ""; for (Class param : parameter) { params += param.getName() + " " + param.getName() + ","; ps += param.getName() + ","; } if (params.equals("")) { params = ""; ps = ""; } else { params = params.substring(0, params.length()); ps = ps.substring(0, ps.length()); } mCtc.addMethod( CtNewMethod.make( modifiers + " void " + method.getName() + "(String a,String b){ Object t=this.getRealClient(); return ((" + ifaces.getName() + ")t)." + method.getName() + "(a,b) ;}", mCtc)); // mCtc.addMethod(CtNewMethod.make("public int count() { return // delegate.count(); }", mCtc)); } Class<?> pc = mCtc.toClass(); mCtc.debugWriteFile("/home/liguojun"); mCtc.writeFile("/home/liguojun"); T bytecodeProxy = (T) pc.newInstance(); Field filed = bytecodeProxy.getClass().getField("sub"); filed.set(bytecodeProxy, loadBalance); Field filed1 = bytecodeProxy.getClass().getField("map"); filed1.set(bytecodeProxy, map); return bytecodeProxy; } catch (Exception e) { e.printStackTrace(); } return null; }