private void writeSetter(ClassVisitor visitor, Type generatedType, ModelProperty<?> property) { WeaklyTypeReferencingMethod<?, Void> weakSetter = property.getSetter(); // There is no setter for this property if (weakSetter == null) { return; } String propertyName = property.getName(); Class<?> propertyClass = property.getType().getConcreteClass(); Type propertyType = Type.getType(propertyClass); Label calledOutsideOfConstructor = new Label(); Method setter = weakSetter.getMethod(); // the regular typed setter String methodDescriptor = Type.getMethodDescriptor(Type.VOID_TYPE, propertyType); MethodVisitor methodVisitor = declareMethod( visitor, setter.getName(), methodDescriptor, AsmClassGeneratorUtils.signature(setter)); putCanCallSettersFieldValueOnStack(methodVisitor, generatedType); jumpToLabelIfStackEvaluatesToTrue(methodVisitor, calledOutsideOfConstructor); throwExceptionBecauseCalledOnItself(methodVisitor); methodVisitor.visitLabel(calledOutsideOfConstructor); putStateFieldValueOnStack(methodVisitor, generatedType); putConstantOnStack(methodVisitor, propertyName); putFirstMethodArgumentOnStack(methodVisitor, propertyType); if (propertyClass.isPrimitive()) { boxType(methodVisitor, propertyClass); } invokeStateSetMethod(methodVisitor); finishVisitingMethod(methodVisitor); }
protected static Object instantiate(Class<?> type) { Object returnValue; try { returnValue = type.newInstance(); } catch (Throwable throwable) { throw new RuntimeException( "Failed to instantiate a new instance of: \'" + type.getName() + "\'", throwable); } return returnValue; }
@Override public <E, L> EventExecutor<E, L> create(EventBus<E, L> eventBus, Method method) { RegisteredListener.validate( Objects.requireNonNull(eventBus, "Null eventBus"), Objects.requireNonNull(method, "Null method")); Class<? extends EventExecutor> executorClass = cache.computeIfAbsent(method, this::generateExecutor); try { return executorClass.newInstance(); } catch (InstantiationException | IllegalAccessException e) { throw new RuntimeException("Unable to initialize " + executorClass, e); } }
// the overload of type Object for Groovy coercions: public void setFoo(Object foo) private void createTypeConvertingSetter( ClassVisitor visitor, Type generatedType, ModelProperty<?> property) { if (!property.isWritable() || !(property.getSchema() instanceof ScalarValueSchema)) { return; } Class<?> propertyClass = property.getType().getConcreteClass(); Type propertyType = Type.getType(propertyClass); Class<?> boxedClass = propertyClass.isPrimitive() ? BOXED_TYPES.get(propertyClass) : propertyClass; Type boxedType = Type.getType(boxedClass); Method setter = property.getSetter().getMethod(); MethodVisitor methodVisitor = declareMethod( visitor, setter.getName(), SET_OBJECT_PROPERTY_DESCRIPTOR, SET_OBJECT_PROPERTY_DESCRIPTOR); putThisOnStack(methodVisitor); putTypeConverterFieldValueOnStack(methodVisitor, generatedType); // Object converted = $typeConverter.convert(foo, Float.class, false); methodVisitor.visitVarInsn(ALOAD, 1); // put var #1 ('foo') on the stack methodVisitor.visitLdcInsn(boxedType); // push the constant Class onto the stack methodVisitor.visitInsn( propertyClass.isPrimitive() ? ICONST_1 : ICONST_0); // push int 1 or 0 (interpreted as true or false) onto the stack methodVisitor.visitMethodInsn( INVOKEINTERFACE, TYPE_CONVERTER_TYPE.getInternalName(), "convert", COERCE_TO_SCALAR_DESCRIPTOR, true); methodVisitor.visitTypeInsn(CHECKCAST, boxedType.getInternalName()); if (propertyClass.isPrimitive()) { unboxType(methodVisitor, propertyClass); } // invoke the typed setter, popping 'this' and 'converted' from the stack methodVisitor.visitMethodInsn( INVOKEVIRTUAL, generatedType.getInternalName(), setter.getName(), Type.getMethodDescriptor(Type.VOID_TYPE, propertyType), false); finishVisitingMethod(methodVisitor); }
private void castFirstStackElement(MethodVisitor methodVisitor, Class<?> returnType) { if (returnType.isPrimitive()) { unboxType(methodVisitor, returnType); } else { methodVisitor.visitTypeInsn(CHECKCAST, Type.getInternalName(returnType)); } }
protected void injectGetByIndex( ClassWriter classWriter, String targetClassName, List<Field> fields) { MethodVisitor methodVisitor = classWriter.visitMethod( ACC_PUBLIC, "get", "(Ljava/lang/Object;I)Ljava/lang/Object;", null, new String[] {getInternalName(ILLEGAL_ACCESS_EXCEPTION.getCanonicalName())}); Boxer boxer = new Boxer(methodVisitor); methodVisitor.visitCode(); methodVisitor.visitVarInsn(ILOAD, 2); int maxStack = 6; Label[] labels = new Label[fields.size()]; Label errorLabel = new Label(); for (int i = 0; i < fields.size(); i++) { labels[i] = new Label(); } methodVisitor.visitTableSwitchInsn(0, labels.length - 1, errorLabel, labels); if (!fields.isEmpty()) { maxStack--; for (int i = 0; i < fields.size(); i++) { Field field = fields.get(i); Class<?> type = field.getType(); String fieldDescriptor = Type.getDescriptor(type); methodVisitor.visitLabel(labels[i]); if (i == 0) methodVisitor.visitFrame(F_APPEND, 1, new Object[] {targetClassName}, 0, null); else methodVisitor.visitFrame(F_SAME, 0, null, 0, null); if (isPublic(field)) { methodVisitor.visitVarInsn(ALOAD, 1); methodVisitor.visitTypeInsn(CHECKCAST, targetClassName); methodVisitor.visitFieldInsn(GETFIELD, targetClassName, field.getName(), fieldDescriptor); boxer.box(Type.getType(type)); } else { injectReflectiveGetter(methodVisitor); } methodVisitor.visitInsn(ARETURN); } methodVisitor.visitLabel(errorLabel); methodVisitor.visitFrame(F_SAME, 0, null, 0, null); } injectException(methodVisitor, IllegalAccessException.class); methodVisitor.visitMaxs(maxStack, 3); methodVisitor.visitEnd(); }
private Class<?> makeClassWithoutAPackage() { // Use ASM since we can't use mockito on Class to make it return a package-less class, Class is // a final class. ClassWriter writer = new ClassWriter(0); writer.visit(V1_5, ACC_PUBLIC, "ClazzWithNoPackage", null, "java/lang/Object", null); writer.visitEnd(); byte[] bytes = writer.toByteArray(); class ClazzLoader extends ClassLoader { Class<?> defineClass(byte[] bytes) { return defineClass(null, bytes, 0, bytes.length); } }; Class<?> clazz = new ClazzLoader().defineClass(bytes); assertEquals("ClazzWithNoPackage", clazz.getName()); return clazz; }
private Method getToStringMethod(Class<?> managedTypeClass) { try { return managedTypeClass.getMethod("toString"); } catch (NoSuchMethodException e) { return null; } }
private void writeDelegateMethods( final ClassVisitor visitor, final Type generatedType, StructSchema<?> delegateSchema, Set<Class<?>> typesToDelegate) { Class<?> delegateClass = delegateSchema.getType().getConcreteClass(); Type delegateType = Type.getType(delegateClass); Map<Equivalence.Wrapper<Method>, Map<Class<?>, Method>> methodsToDelegate = Maps.newHashMap(); for (Class<?> typeToDelegate : typesToDelegate) { for (Method methodToDelegate : typeToDelegate.getMethods()) { if (ModelSchemaUtils.isIgnoredMethod(methodToDelegate)) { continue; } Equivalence.Wrapper<Method> methodKey = METHOD_EQUIVALENCE.wrap(methodToDelegate); Map<Class<?>, Method> methodsByReturnType = methodsToDelegate.get(methodKey); if (methodsByReturnType == null) { methodsByReturnType = Maps.newHashMap(); methodsToDelegate.put(methodKey, methodsByReturnType); } methodsByReturnType.put(methodToDelegate.getReturnType(), methodToDelegate); } } Set<Equivalence.Wrapper<Method>> delegateMethodKeys = ImmutableSet.copyOf( Iterables.transform( Arrays.asList(delegateClass.getMethods()), new Function<Method, Equivalence.Wrapper<Method>>() { @Override public Equivalence.Wrapper<Method> apply(Method method) { return METHOD_EQUIVALENCE.wrap(method); } })); for (Map.Entry<Equivalence.Wrapper<Method>, Map<Class<?>, Method>> entry : methodsToDelegate.entrySet()) { Equivalence.Wrapper<Method> methodKey = entry.getKey(); if (!delegateMethodKeys.contains(methodKey)) { continue; } Map<Class<?>, Method> methodsByReturnType = entry.getValue(); for (Method methodToDelegate : methodsByReturnType.values()) { writeDelegatedMethod(visitor, generatedType, delegateType, methodToDelegate); } } }
static { ASMEventExecutorFactory instance = null; try { Class.forName("org.objectweb.asm.Opcodes"); instance = new ASMEventExecutorFactory(); } catch (ClassNotFoundException ignored) { } INSTANCE = instance; }
@Override public FieldAccessor build(ClassLoader classLoader) { String targetClassType = getInternalName(this.getTarget().getName()); ClassWriter classWriter = this.getClassWriter(); injectFieldTable(classWriter); injectConstructor(classWriter); injectGetTargetClass(classWriter, this.getTarget()); List<Field> fields = new ArrayList<>(); Class<?> current = this.getTarget(); while (current != Object.class) { for (Field field : current.getDeclaredFields()) { fields.add(field); } current = current.getSuperclass(); } injectGetByIndex(classWriter, targetClassType, fields); injectSetByIndex(classWriter, targetClassType, fields); injectGetByName(classWriter); injectSetByName(classWriter); injectGetFieldTable(classWriter); injectGetIndex(classWriter); classWriter.visitEnd(); Class<?> result = CompilerService.create(classLoader) .defineClass( getExternalName( getAccessorNameInternal( this.getTarget(), this .getAccessorType())), // this is somewhat redundant but maybe in the // future the class-name-format changes this.getClassWriter().toByteArray()); return (FieldAccessor) instantiate(result); }
protected void injectException( MethodVisitor methodVisitor, Class<? extends Throwable> throwable) { methodVisitor.visitTypeInsn(NEW, getInternalName(throwable.getCanonicalName())); methodVisitor.visitInsn(DUP); methodVisitor.visitTypeInsn(NEW, "java/lang/StringBuilder"); methodVisitor.visitInsn(DUP); methodVisitor.visitLdcInsn("Invalid index: "); methodVisitor.visitMethodInsn( INVOKESPECIAL, "java/lang/StringBuilder", "<init>", "(Ljava/lang/String;)V"); methodVisitor.visitVarInsn(ILOAD, 2); methodVisitor.visitMethodInsn( INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(I)Ljava/lang/StringBuilder;"); methodVisitor.visitMethodInsn( INVOKEVIRTUAL, "java/lang/StringBuilder", "toString", "()Ljava/lang/String;"); methodVisitor.visitMethodInsn( INVOKESPECIAL, getInternalName(throwable.getCanonicalName()), "<init>", "(Ljava/lang/String;)V"); methodVisitor.visitInsn(ATHROW); }
private static void resetLambdaClassSequenceNumber() { try { Field counterField = Class.forName("java.lang.invoke.InnerClassLambdaMetafactory").getDeclaredField("counter"); counterField.setAccessible(true); AtomicInteger counter = (AtomicInteger) counterField.get(null); counter.set(0); } catch (Throwable t) { // print to stdout to keep in sync with other log output System.out.println( "WARNING: Failed to start class numbering from one. Don't worry, it's cosmetic, " + "but please file a bug report and tell on which JDK version this happened."); t.printStackTrace(System.out); } }
private void unboxType(MethodVisitor methodVisitor, Class<?> primitiveClass) { // Float f = (Float) tmp // f==null?0:f.floatValue() Class<?> boxedType = BOXED_TYPES.get(primitiveClass); Type primitiveType = Type.getType(primitiveClass); methodVisitor.visitTypeInsn(CHECKCAST, Type.getInternalName(boxedType)); methodVisitor.visitInsn(DUP); Label exit = new Label(); Label elseValue = new Label(); methodVisitor.visitJumpInsn(IFNONNULL, elseValue); methodVisitor.visitInsn(POP); pushDefaultValue(methodVisitor, primitiveClass); methodVisitor.visitJumpInsn(GOTO, exit); methodVisitor.visitLabel(elseValue); methodVisitor.visitMethodInsn( INVOKEVIRTUAL, Type.getInternalName(boxedType), primitiveClass.getSimpleName() + "Value", Type.getMethodDescriptor(primitiveType), false); methodVisitor.visitLabel(exit); }
public static FieldAccess get(Class type) { ArrayList<Field> fields = new ArrayList<Field>(); Class nextClass = type; while (nextClass != Object.class) { Field[] declaredFields = nextClass.getDeclaredFields(); fields.addAll(Arrays.asList(declaredFields)); nextClass = nextClass.getSuperclass(); } String[] fieldNames = new String[fields.size()]; Class[] fieldTypes = new Class[fields.size()]; for (int i = 0, n = fieldNames.length; i < n; i++) { fieldNames[i] = fields.get(i).getName(); fieldTypes[i] = fields.get(i).getType(); } String className = type.getName(); String accessClassName = className + "FieldAccess"; if (accessClassName.startsWith("java.")) accessClassName = "reflectasm." + accessClassName; Class accessClass = null; AccessClassLoader loader = AccessClassLoader.get(type); synchronized (loader) { try { accessClass = loader.loadClass(accessClassName); } catch (ClassNotFoundException ignored) { String accessClassNameInternal = accessClassName.replace('.', '/'); String classNameInternal = className.replace('.', '/'); ClassWriter cw = new ClassWriter(0); cw.visit( V1_1, ACC_PUBLIC + ACC_SUPER, accessClassNameInternal, null, "com/esotericsoftware/reflectasm/FieldAccess", null); insertConstructor(cw); insertGetObject(cw, classNameInternal, fields); insertSetObject(cw, classNameInternal, fields); insertGetPrimitive(cw, classNameInternal, fields, Type.BOOLEAN_TYPE); insertSetPrimitive(cw, classNameInternal, fields, Type.BOOLEAN_TYPE); insertGetPrimitive(cw, classNameInternal, fields, Type.BYTE_TYPE); insertSetPrimitive(cw, classNameInternal, fields, Type.BYTE_TYPE); insertGetPrimitive(cw, classNameInternal, fields, Type.SHORT_TYPE); insertSetPrimitive(cw, classNameInternal, fields, Type.SHORT_TYPE); insertGetPrimitive(cw, classNameInternal, fields, Type.INT_TYPE); insertSetPrimitive(cw, classNameInternal, fields, Type.INT_TYPE); insertGetPrimitive(cw, classNameInternal, fields, Type.LONG_TYPE); insertSetPrimitive(cw, classNameInternal, fields, Type.LONG_TYPE); insertGetPrimitive(cw, classNameInternal, fields, Type.DOUBLE_TYPE); insertSetPrimitive(cw, classNameInternal, fields, Type.DOUBLE_TYPE); insertGetPrimitive(cw, classNameInternal, fields, Type.FLOAT_TYPE); insertSetPrimitive(cw, classNameInternal, fields, Type.FLOAT_TYPE); insertGetPrimitive(cw, classNameInternal, fields, Type.CHAR_TYPE); insertSetPrimitive(cw, classNameInternal, fields, Type.CHAR_TYPE); insertGetString(cw, classNameInternal, fields); cw.visitEnd(); accessClass = loader.defineClass(accessClassName, cw.toByteArray()); } } try { FieldAccess access = (FieldAccess) accessClass.newInstance(); access.fieldNames = fieldNames; access.fieldTypes = fieldTypes; return access; } catch (Throwable t) { throw new RuntimeException("Error constructing field access class: " + accessClassName, t); } }
protected static String toSafeName(Class<?> clazz) { return clazz.getCanonicalName().replace("[]", "Array").replace(".", "_"); }
/** * Generates an implementation of the given managed type. * * <p>The generated class will implement/extend the managed type and will: * * <ul> * <li>provide implementations for abstract getters and setters that delegate to model nodes * <li>provide a `toString()` implementation * <li>mix-in implementation of {@link ManagedInstance} * <li>provide a constructor that accepts a {@link ModelElementState}, which will be used to * implement the above. * </ul> * * In case a delegate schema is supplied, the generated class will also have: * * <ul> * <li>a constructor that also takes a delegate instance * <li>methods that call through to the delegate instance * </ul> */ public <T, M extends T, D extends T> Class<? extends M> generate( StructSchema<M> viewSchema, @Nullable StructSchema<D> delegateSchema) { if (delegateSchema != null && Modifier.isAbstract(delegateSchema.getType().getConcreteClass().getModifiers())) { throw new IllegalArgumentException("Delegate type must be null or a non-abstract type"); } ClassWriter visitor = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES); ModelType<M> viewType = viewSchema.getType(); StringBuilder generatedTypeNameBuilder = new StringBuilder(viewType.getName()); if (delegateSchema != null) { generatedTypeNameBuilder .append("$BackedBy_") .append(delegateSchema.getType().getName().replaceAll("\\.", "_")); } else { generatedTypeNameBuilder.append("$Impl"); } String generatedTypeName = generatedTypeNameBuilder.toString(); Type generatedType = Type.getType("L" + generatedTypeName.replaceAll("\\.", "/") + ";"); Class<M> viewClass = viewType.getConcreteClass(); Class<?> superclass; final ImmutableSet.Builder<String> interfacesToImplement = ImmutableSet.builder(); final ImmutableSet.Builder<Class<?>> typesToDelegate = ImmutableSet.builder(); typesToDelegate.add(viewClass); interfacesToImplement.add(MANAGED_INSTANCE_TYPE); if (viewClass.isInterface()) { superclass = Object.class; interfacesToImplement.add(Type.getInternalName(viewClass)); } else { superclass = viewClass; } // TODO:LPTR This should be removed once BinaryContainer is a ModelMap // We need to also implement all the interfaces of the delegate type because otherwise // BinaryContainer won't recognize managed binaries as BinarySpecInternal if (delegateSchema != null) { ModelSchemaUtils.walkTypeHierarchy( delegateSchema.getType().getConcreteClass(), new ModelSchemaUtils.TypeVisitor<D>() { @Override public void visitType(Class<? super D> type) { if (type.isInterface()) { typesToDelegate.add(type); interfacesToImplement.add(Type.getInternalName(type)); } } }); } generateProxyClass( visitor, viewSchema, delegateSchema, interfacesToImplement.build(), typesToDelegate.build(), generatedType, Type.getType(superclass)); ClassLoader targetClassLoader = viewClass.getClassLoader(); if (delegateSchema != null) { // TODO - remove this once the above is removed try { viewClass.getClassLoader().loadClass(delegateSchema.getType().getConcreteClass().getName()); } catch (ClassNotFoundException e) { // Delegate class is not visible to managed view type -> view type is more general than // delegate type, so use the delegate classloader instead targetClassLoader = delegateSchema.getType().getConcreteClass().getClassLoader(); } } return defineClass(visitor, targetClassLoader, generatedTypeName); }
private void putClassOnStack(MethodVisitor methodVisitor, Class<?> managedTypeClass) { putConstantOnStack(methodVisitor, managedTypeClass.getName()); methodVisitor.visitMethodInsn( INVOKESTATIC, CLASS_INTERNAL_NAME, "forName", FOR_NAME_METHOD_DESCRIPTOR, false); }
@SuppressWarnings({"rawtypes", "unchecked"}) public static <T> ConstructorAccess<T> get(Class<T> type) { try { type.getConstructor((Class[]) null); } catch (Exception ex) { if (type.isMemberClass() && !Modifier.isStatic(type.getModifiers())) throw new RuntimeException( "Class cannot be created (non-static member class): " + type.getName()); else throw new RuntimeException( "Class cannot be created (missing no-arg constructor): " + type.getName()); } AccessClassLoader loader = AccessClassLoader.get(type); String className = type.getName(); String accessClassName = className + "ConstructorAccess"; if (accessClassName.startsWith("java.")) accessClassName = "reflectasm." + accessClassName; Class accessClass = null; try { accessClass = loader.loadClass(accessClassName); } catch (ClassNotFoundException ignored) { } if (accessClass == null) { String accessClassNameInternal = accessClassName.replace('.', '/'); String classNameInternal = className.replace('.', '/'); ClassWriter cw = new ClassWriter(0); cw.visit( V1_1, ACC_PUBLIC + ACC_SUPER, accessClassNameInternal, null, "com/esotericsoftware/reflectasm/ConstructorAccess", null); MethodVisitor mv; { mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null); mv.visitCode(); mv.visitVarInsn(ALOAD, 0); mv.visitMethodInsn( INVOKESPECIAL, "com/esotericsoftware/reflectasm/ConstructorAccess", "<init>", "()V"); mv.visitInsn(RETURN); mv.visitMaxs(1, 1); mv.visitEnd(); } { mv = cw.visitMethod(ACC_PUBLIC, "newInstance", "()Ljava/lang/Object;", null, null); mv.visitCode(); mv.visitTypeInsn(NEW, classNameInternal); mv.visitInsn(DUP); mv.visitMethodInsn(INVOKESPECIAL, classNameInternal, "<init>", "()V"); mv.visitInsn(ARETURN); mv.visitMaxs(2, 1); mv.visitEnd(); } cw.visitEnd(); byte[] data = cw.toByteArray(); accessClass = loader.defineClass(accessClassName, data); } try { return (ConstructorAccess) accessClass.newInstance(); } catch (Exception ex) { throw new RuntimeException( "Error constructing constructor access class: " + accessClassName, ex); } }