@After public void tearDown() throws Exception { final CtClass packageInfoCtClass = ClassPool.getDefault().get("com.edugility.jaxb.package-info"); assertNotNull(packageInfoCtClass); packageInfoCtClass.detach(); }
static TypeParameterMatcher generate(Class<?> type, ClassLoader classLoader) { final String className = "io.netty.util.internal.__matchers__." + type.getName() + "Matcher"; try { try { return (TypeParameterMatcher) Class.forName(className, true, classLoader).newInstance(); } catch (Exception e) { // Not defined in the specified class loader. } CtClass c = classPool.getAndRename(NoOpTypeParameterMatcher.class.getName(), className); c.setModifiers(c.getModifiers() | Modifier.FINAL); c.getDeclaredMethod("match").setBody("{ return $1 instanceof " + type.getName() + "; }"); byte[] byteCode = c.toBytecode(); c.detach(); Method method = ClassLoader.class.getDeclaredMethod( "defineClass", String.class, byte[].class, int.class, int.class); method.setAccessible(true); Class<?> generated = (Class<?>) method.invoke(classLoader, className, byteCode, 0, byteCode.length); logger.debug("Generated: {}", generated.getName()); return (TypeParameterMatcher) generated.newInstance(); } catch (RuntimeException e) { throw e; } catch (Exception e) { throw new RuntimeException(e); } }
private void enhanceClass(Enhancer enhancer, File file) { byte[] enhancedBytecode = null; InputStream is = null; CtClass clas = null; try { is = new FileInputStream(file.toString()); clas = getClassPool().makeClass(is); if (!clas.hasAnnotation(Entity.class)) { getLog().debug("Class $file not an annotated Entity class. skipping..."); } else { enhancedBytecode = enhancer.enhance(clas.getName(), clas.toBytecode()); } } catch (Exception e) { getLog().error("Unable to enhance class [${file.toString()}]", e); return; } finally { try { if (null != is) is.close(); } catch (IOException ioe) { } } if (null != enhancedBytecode) { if (file.delete()) { try { if (!file.createNewFile()) { getLog().error("Unable to recreate class file [" + clas.getName() + "]"); } } catch (IOException ioe) { } } else { getLog().error("Unable to delete class file [" + clas.getName() + "]"); } FileOutputStream outputStream = null; try { outputStream = new FileOutputStream(file, false); outputStream.write(enhancedBytecode); outputStream.flush(); } catch (IOException ioe) { } finally { try { if (outputStream != null) outputStream.close(); clas.detach(); // release memory } catch (IOException ignore) { } } } }
@Override public byte[] transform( ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { byte[] bytes = null; try { final ClassPool pool = ClassPool.getDefault(); pool.appendClassPath(new LoaderClassPath(getClass().getClassLoader())); final CtClass ctClass = pool.getCtClass(className.replaceAll("/", ".")); if (ctClass != null) { try { for (CtMethod ctMethod : ctClass.getMethods()) { if (ctMethod.hasAnnotation(Retryable.class)) { try { changeMethod(ctClass, ctMethod); bytes = ctClass.toBytecode(); writeClassFile(bytes); } catch (CannotCompileException | IOException e) { e.printStackTrace(); } System.out.println("found it!"); } } } finally { ctClass.detach(); } } } catch (NotFoundException e) { e.printStackTrace(); } return bytes; }
private void processAndWriteClass(Directory baseDir, File classfile) throws Exception { CtClass clazz = classPool.get(ClassNames.getClassName(baseDir, classfile)); classInstrumenter.instrumentClass(clazz); if (clazz.isModified()) clazz.writeFile(processDirectory.getAbsolutePath()); clazz.detach(); }
@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; }
private void enhance_(ApplicationClass applicationClass, boolean buildAuthorityRegistryOnly) throws Exception { Plugin.trace("about to enhance applicationClass: %s", applicationClass); CtClass ctClass = makeClass(applicationClass); Set<CtBehavior> s = new HashSet<CtBehavior>(); s.addAll(Arrays.asList(ctClass.getDeclaredMethods())); s.addAll(Arrays.asList(ctClass.getMethods())); s.addAll(Arrays.asList(ctClass.getConstructors())); s.addAll(Arrays.asList(ctClass.getDeclaredConstructors())); for (final CtBehavior ctBehavior : s) { if (!Modifier.isPublic(ctBehavior.getModifiers()) || javassist.Modifier.isAbstract(ctBehavior.getModifiers())) { continue; } boolean needsEnhance = false; RequireRight rr = null; RequirePrivilege rp = null; RequireAccounting ra = null; boolean allowSystem = false; Object[] aa = ctBehavior.getAnnotations(); for (Object o : aa) { if (o instanceof RequirePrivilege) { needsEnhance = true; rp = (RequirePrivilege) o; continue; } if (o instanceof RequireRight) { needsEnhance = true; rr = (RequireRight) o; continue; } if (o instanceof AllowSystemAccount) { allowSystem = true; continue; } if (o instanceof RequireAccounting) { needsEnhance = true; ra = (RequireAccounting) o; } } if (!needsEnhance) continue; String key = ctBehavior.getLongName(); String errMsg = String.format("Error enhancing class %s.%s: ", ctClass, ctBehavior); // process rr & rp if (null != rr || null != rp) { // check before/after enhancement Authority.registAuthoriable_(key, rr, rp); if (!buildAuthorityRegistryOnly) { // verify if before attribute of rr and rp is consistent if (null != rr && null != rp && (rr.before() != rp.before())) { String reason = "The before setting of RequireRight and RequirePrivilege doesn't match"; throw new RuntimeException(errMsg + reason); } boolean before = true; if (null != rr) before = rr.before(); if (null != rp) before = rp.before(); // try best to guess the target object String curObj = ""; if (null != rr) { // target object only impact dynamic access checking, hence rr shall not be null boolean isConstructor = ctBehavior instanceof CtConstructor; boolean isStatic = false; if (!isConstructor) isStatic = Modifier.isStatic(ctBehavior.getModifiers()); int paraCnt = ctBehavior.getParameterTypes().length; int id = rr.target(); // calibrate target id if (0 == id) { if (isConstructor) { id = -1; } else if (isStatic) { if (paraCnt > 0) id = 1; else id = -1; } } else if (id > paraCnt) { id = paraCnt; } // speculate cur target statement String sid = null; if (id == -1) sid = "_"; if (id > -1) sid = String.valueOf(id); if (null != sid) { curObj = "play.modules.aaa.PlayDynamicRightChecker.setObjectIfNoCurrent($" + sid + ");"; } if (-1 == id) before = false; } // check permission enhancement if (before) { ctBehavior.insertBefore( curObj + " play.modules.aaa.enhancer.Enhancer.Authority.checkPermission(\"" + key + "\", " + Boolean.toString(allowSystem) + ");"); } else { ctBehavior.insertAfter( curObj + " play.modules.aaa.enhancer.Enhancer.Authority.checkPermission(\"" + key + "\", " + Boolean.toString(allowSystem) + ");"); } } } if (buildAuthorityRegistryOnly) continue; // process ra if (null != ra) { CtClass[] paraTypes = ctBehavior.getParameterTypes(); String sParam = null; if (0 < paraTypes.length) { sParam = "new Object[0]"; } else { sParam = "{$$}"; } String msg = ra.value(); if (null == msg || "".equals(msg)) msg = key; if (ra.before()) { ctBehavior.insertBefore( "play.modules.aaa.utils.Accounting.info(\"" + msg + "\", " + Boolean.toString(allowSystem) + ", " + sParam + ");"); } else { ctBehavior.insertAfter( "play.modules.aaa.utils.Accounting.info(\"" + msg + "\", " + Boolean.toString(allowSystem) + ", " + sParam + ");"); } CtClass etype = ClassPool.getDefault().get("java.lang.Exception"); ctBehavior.addCatch( "{play.modules.aaa.utils.Accounting.error($e, \"" + msg + "\", " + Boolean.toString(allowSystem) + ", " + sParam + "); throw $e;}", etype); } } if (buildAuthorityRegistryOnly) return; applicationClass.enhancedByteCode = ctClass.toBytecode(); ctClass.detach(); }