private void writePropertyMethods( ClassVisitor visitor, Type generatedType, StructSchema<?> viewSchema, StructSchema<?> delegateSchema) { Collection<String> delegatePropertyNames; if (delegateSchema != null) { delegatePropertyNames = delegateSchema.getPropertyNames(); } else { delegatePropertyNames = Collections.emptySet(); } Class<?> viewClass = viewSchema.getType().getConcreteClass(); for (ModelProperty<?> property : viewSchema.getProperties()) { String propertyName = property.getName(); writeConfigureMethod(visitor, generatedType, property); writeSetMethod(visitor, generatedType, property); createTypeConvertingSetter(visitor, generatedType, property); // Delegated properties are handled in writeDelegateMethods() if (delegatePropertyNames.contains(propertyName)) { continue; } switch (property.getStateManagementType()) { case MANAGED: writeGetters(visitor, generatedType, property); writeSetter(visitor, generatedType, property); break; case UNMANAGED: for (WeaklyTypeReferencingMethod<?, ?> getter : property.getGetters()) { Method getterMethod = getter.getMethod(); if (!Modifier.isFinal(getterMethod.getModifiers()) && !propertyName.equals("metaClass")) { writeNonAbstractMethodWrapper(visitor, generatedType, viewClass, getterMethod); } } break; } } }
private void writeGetters(ClassVisitor visitor, Type generatedType, ModelProperty<?> property) { Class<?> propertyClass = property.getType().getConcreteClass(); Type propertyType = Type.getType(propertyClass); Set<String> processedNames = Sets.newHashSet(); for (WeaklyTypeReferencingMethod<?, ?> weakGetter : property.getGetters()) { Method getter = weakGetter.getMethod(); if (!processedNames.add(getter.getName())) { continue; } MethodVisitor methodVisitor = declareMethod( visitor, getter.getName(), Type.getMethodDescriptor(propertyType), AsmClassGeneratorUtils.signature(getter)); putStateFieldValueOnStack(methodVisitor, generatedType); putConstantOnStack(methodVisitor, property.getName()); invokeStateGetMethod(methodVisitor); castFirstStackElement(methodVisitor, propertyClass); finishVisitingMethod(methodVisitor, returnCode(propertyType)); } }
private void writeConfigureMethod( ClassVisitor visitor, Type generatedType, ModelProperty<?> property) { if (!property.isWritable() && property.getSchema() instanceof CompositeSchema) { // Adds a void $propName(Closure<?> cl) method that delegates to model state MethodVisitor methodVisitor = declareMethod( visitor, property.getName(), Type.getMethodDescriptor(Type.VOID_TYPE, CLOSURE_TYPE), null); putStateFieldValueOnStack(methodVisitor, generatedType); putConstantOnStack(methodVisitor, property.getName()); putFirstMethodArgumentOnStack(methodVisitor); methodVisitor.visitMethodInsn( INVOKEINTERFACE, MODEL_ELEMENT_STATE_TYPE_INTERNAL_NAME, "apply", STATE_APPLY_METHOD_DESCRIPTOR, true); finishVisitingMethod(methodVisitor); return; } if (!property.isWritable() && property.getSchema() instanceof UnmanagedImplStructSchema) { UnmanagedImplStructSchema<?> structSchema = (UnmanagedImplStructSchema<?>) property.getSchema(); if (!structSchema.isAnnotated()) { return; } // Adds a void $propName(Closure<?> cl) method that executes the closure MethodVisitor methodVisitor = declareMethod( visitor, property.getName(), Type.getMethodDescriptor(Type.VOID_TYPE, CLOSURE_TYPE), null); putThisOnStack(methodVisitor); methodVisitor.visitMethodInsn( INVOKEVIRTUAL, generatedType.getInternalName(), property.getGetters().get(0).getName(), Type.getMethodDescriptor(Type.getType(property.getType().getConcreteClass())), false); putFirstMethodArgumentOnStack(methodVisitor); methodVisitor.visitMethodInsn( INVOKESTATIC, Type.getInternalName(ClosureBackedAction.class), "execute", Type.getMethodDescriptor(Type.VOID_TYPE, OBJECT_TYPE, CLOSURE_TYPE), false); finishVisitingMethod(methodVisitor); return; } // Adds a void $propName(Closure<?> cl) method that throws MME, to avoid attempts to convert // closure to something else MethodVisitor methodVisitor = declareMethod( visitor, property.getName(), Type.getMethodDescriptor(Type.VOID_TYPE, CLOSURE_TYPE), null); putThisOnStack(methodVisitor); putConstantOnStack(methodVisitor, property.getName()); methodVisitor.visitInsn(Opcodes.ICONST_1); methodVisitor.visitTypeInsn(Opcodes.ANEWARRAY, OBJECT_TYPE.getInternalName()); methodVisitor.visitInsn(Opcodes.DUP); methodVisitor.visitInsn(Opcodes.ICONST_0); putFirstMethodArgumentOnStack(methodVisitor); methodVisitor.visitInsn(Opcodes.AASTORE); methodVisitor.visitMethodInsn( INVOKEVIRTUAL, generatedType.getInternalName(), "methodMissing", METHOD_MISSING_METHOD_DESCRIPTOR, false); finishVisitingMethod(methodVisitor); }