/** * Determines if a Class is a Cglib GeneratorStrategy subclass * * @param cc * @return */ private static boolean isGeneratorStrategy(CtClass cc) { String[] interfaces = cc.getClassFile2().getInterfaces(); for (String interfaceName : interfaces) { // We use class name strings because some libraries repackage cglib to a different namespace to avoid // conflicts. if (interfaceName.endsWith(".GeneratorStrategy")) { @SuppressWarnings("unchecked") List<MethodInfo> methodInfos = cc.getClassFile2().getMethods(); for (MethodInfo method : methodInfos) { if (method.getName().equals("generate") && method.getDescriptor().endsWith("[B")) { return true; } } } } return false; }
/** * Remove final flag from SessionFactoryImpl - we need to create a proxy on session factory and cannot * use SessionFactory interface, because hibernate makes type cast to impl. */ @OnClassLoadEvent(classNameRegexp = "org.hibernate.internal.SessionFactoryImpl") public static void removeSessionFactoryImplFinalFlag(CtClass clazz) throws Exception { clazz.getClassFile().setAccessFlags(AccessFlag.PUBLIC); }
/** * Ensure proxyable. * * @param clazz * the clazz * @throws CannotCompileException * the cannot compile exception */ public static void ensureProxyable(CtClass clazz) throws CannotCompileException { int flags = clazz.getClassFile().getAccessFlags(); flags = AccessFlag.setPublic(flags); flags = AccessFlag.clear(flags, AccessFlag.FINAL); clazz.getClassFile().setAccessFlags(flags); try { CtConstructor ct = clazz.getDeclaredConstructor(new CtClass[] {}); if (Modifier.isPrivate(ct.getModifiers())) { ct.setModifiers(AccessFlag.setProtected(ct.getModifiers())); } } catch (NotFoundException ex) { CtConstructor c = CtNewConstructor.make("protected " + clazz.getSimpleName() + "() {}", clazz); clazz.addConstructor(c); } }
/** * Generate code to invoke the Class.forName with the name of the given * class to get its Class object at runtime. The code is written to the * supplied stream. Note that the code generated by this method may caused * the checked ClassNotFoundException to be thrown. */ private void codeClassForName(CtClass cl, DataOutputStream out) throws IOException { if (cl.isArray()) { code_ldc(cp.getString(Descriptor.of(cl).replace("/", ".")), out); } else code_ldc(cp.getString(cl.getName()), out); out.writeByte(opc_invokestatic); out.writeShort(cp.getMethodRef("java/lang/Class", "forName", "(Ljava/lang/String;)Ljava/lang/Class;")); }
/** * Adds bytecode generation call parameter recording * * @param cc * @return * @throws Exception */ public static CtClass transform(CtClass cc) throws Exception { if (isGeneratorStrategy(cc)) { for (CtMethod method : cc.getDeclaredMethods()) { if (!Modifier.isAbstract(method.getModifiers()) && method.getName().equals("generate") && method.getMethodInfo().getDescriptor().endsWith(";)[B")) { cc.defrost(); method.insertAfter("org.hotswap.agent.plugin.proxy.hscglib.GeneratorParametersRecorder.register($0, $1, $_);"); } } } return cc; }
/** * Return the "field type" string for the given type, appropriate for a * field descriptor, a parameter descriptor, or a return descriptor other * than "void". See JVMS section 4.3.2. */ private static String getFieldType(CtClass type) { if (type.isPrimitive()) { return PrimitiveTypeInfo.get(type).baseTypeString; } else if (type.isArray()) { /* * According to JLS 20.3.2, the getName() method on Class does * return the VM type descriptor format for array classes (only); * using that should be quicker than the otherwise obvious code: * * return "[" + getTypeDescriptor(type.getComponentType()); */ return Descriptor.of(type); } else { return "L" + dotToSlash(type.getName()) + ";"; } }