public void addGetter(MetaBeanProperty property) throws Exception { MetaMethod getter = property.getGetter(); // GENERATE private boolean <prop>Set; String flagName = String.format("%sSet", property.getName()); visitor.visitField( Opcodes.ACC_PRIVATE, flagName, Type.BOOLEAN_TYPE.getDescriptor(), null, null); addConventionGetter(getter.getName(), flagName, property); String getterName = getter.getName(); Class<?> returnType = getter.getReturnType(); // If it's a boolean property, there can be get or is type variants. // If this class has both, decorate both. if (returnType.equals(Boolean.TYPE)) { boolean getterIsIsMethod = getterName.startsWith("is"); String propertyNameComponent = getterName.substring(getterIsIsMethod ? 2 : 3); String alternativeGetterName = String.format("%s%s", getterIsIsMethod ? "get" : "is", propertyNameComponent); try { type.getMethod(alternativeGetterName); addConventionGetter(alternativeGetterName, flagName, property); } catch (NoSuchMethodException e) { // ignore, no method to override } } }
public Map<String, ?> getProperties() { if (!includeProperties) { return Collections.emptyMap(); } Map<String, Object> properties = new HashMap<String, Object>(); List<MetaProperty> classProperties = getMetaClass().getProperties(); for (MetaProperty metaProperty : classProperties) { if (metaProperty.getName().equals("properties")) { properties.put("properties", properties); continue; } if (metaProperty instanceof MetaBeanProperty) { MetaBeanProperty beanProperty = (MetaBeanProperty) metaProperty; if (beanProperty.getGetter() == null) { continue; } } properties.put(metaProperty.getName(), metaProperty.getProperty(bean)); } return properties; }
private void addConventionGetter(String getterName, String flagName, MetaBeanProperty property) throws Exception { // GENERATE public <type> <getter>() { return // (<type>)getConventionMapping().getConventionValue(super.<getter>(), '<prop>', <prop>Set); } MetaMethod getter = property.getGetter(); Type returnType = Type.getType(getter.getReturnType()); String methodDescriptor = Type.getMethodDescriptor(returnType, new Type[0]); MethodVisitor methodVisitor = visitor.visitMethod( Opcodes.ACC_PUBLIC, getterName, methodDescriptor, null, new String[0]); methodVisitor.visitCode(); methodVisitor.visitVarInsn(Opcodes.ALOAD, 0); methodVisitor.visitMethodInsn( Opcodes.INVOKEINTERFACE, conventionAwareType.getInternalName(), "getConventionMapping", Type.getMethodDescriptor(conventionMappingType, new Type[0])); methodVisitor.visitVarInsn(Opcodes.ALOAD, 0); methodVisitor.visitMethodInsn( Opcodes.INVOKESPECIAL, superclassType.getInternalName(), getterName, methodDescriptor); Type boxedType = null; if (getter.getReturnType().isPrimitive()) { // Box value boxedType = Type.getType(JavaReflectionUtil.getWrapperTypeForPrimitiveType(getter.getReturnType())); String valueOfMethodDescriptor = Type.getMethodDescriptor(boxedType, new Type[] {returnType}); methodVisitor.visitMethodInsn( Opcodes.INVOKESTATIC, boxedType.getInternalName(), "valueOf", valueOfMethodDescriptor); } methodVisitor.visitLdcInsn(property.getName()); methodVisitor.visitVarInsn(Opcodes.ALOAD, 0); methodVisitor.visitFieldInsn( Opcodes.GETFIELD, generatedType.getInternalName(), flagName, Type.BOOLEAN_TYPE.getDescriptor()); String getConventionValueDesc = Type.getMethodDescriptor( ConventionMapping.class.getMethod( "getConventionValue", Object.class, String.class, Boolean.TYPE)); methodVisitor.visitMethodInsn( Opcodes.INVOKEINTERFACE, conventionMappingType.getInternalName(), "getConventionValue", getConventionValueDesc); if (getter.getReturnType().isPrimitive()) { // Unbox value methodVisitor.visitTypeInsn(Opcodes.CHECKCAST, boxedType.getInternalName()); String valueMethodDescriptor = Type.getMethodDescriptor(returnType, new Type[0]); methodVisitor.visitMethodInsn( Opcodes.INVOKEVIRTUAL, boxedType.getInternalName(), getter.getReturnType().getName() + "Value", valueMethodDescriptor); } else { // Cast to return type methodVisitor.visitTypeInsn( Opcodes.CHECKCAST, getter.getReturnType().isArray() ? "[" + returnType.getElementType().getDescriptor() : returnType.getInternalName()); } methodVisitor.visitInsn(returnType.getOpcode(Opcodes.IRETURN)); methodVisitor.visitMaxs(0, 0); methodVisitor.visitEnd(); }
public <T> Class<? extends T> generate(Class<T> type) { Map<Class, Class> cache = GENERATED_CLASSES.get(getClass()); if (cache == null) { cache = new HashMap<Class, Class>(); GENERATED_CLASSES.put(getClass(), cache); } Class generatedClass = cache.get(type); if (generatedClass != null) { return generatedClass; } if (Modifier.isPrivate(type.getModifiers())) { throw new GradleException( String.format( "Cannot create a proxy class for private class '%s'.", type.getSimpleName())); } if (Modifier.isAbstract(type.getModifiers())) { throw new GradleException( String.format( "Cannot create a proxy class for abstract class '%s'.", type.getSimpleName())); } Class<? extends T> subclass; try { ClassBuilder<T> builder = start(type); boolean isConventionAware = type.getAnnotation(NoConventionMapping.class) == null; boolean isDynamicAware = type.getAnnotation(NoDynamicObject.class) == null; builder.startClass(isConventionAware, isDynamicAware); if (isDynamicAware && !DynamicObjectAware.class.isAssignableFrom(type)) { builder.mixInDynamicAware(); } if (isDynamicAware && !GroovyObject.class.isAssignableFrom(type)) { builder.mixInGroovyObject(); } if (isDynamicAware) { builder.addDynamicMethods(); } if (isConventionAware && !IConventionAware.class.isAssignableFrom(type)) { builder.mixInConventionAware(); } Class noMappingClass = Object.class; for (Class<?> c = type; c != null && noMappingClass == Object.class; c = c.getSuperclass()) { if (c.getAnnotation(NoConventionMapping.class) != null) { noMappingClass = c; } } Collection<String> skipProperties = Arrays.asList("metaClass", "conventionMapping", "convention", "asDynamicObject"); MetaClass metaClass = GroovySystem.getMetaClassRegistry().getMetaClass(type); for (MetaProperty property : metaClass.getProperties()) { if (skipProperties.contains(property.getName())) { continue; } if (property instanceof MetaBeanProperty) { MetaBeanProperty metaBeanProperty = (MetaBeanProperty) property; MetaMethod getter = metaBeanProperty.getGetter(); if (getter == null) { continue; } if (Modifier.isFinal(getter.getModifiers()) || Modifier.isPrivate(getter.getModifiers())) { continue; } if (getter.getReturnType().isPrimitive()) { continue; } Class declaringClass = getter.getDeclaringClass().getTheClass(); if (declaringClass.isAssignableFrom(noMappingClass)) { continue; } builder.addGetter(metaBeanProperty); MetaMethod setter = metaBeanProperty.getSetter(); if (setter == null) { continue; } if (Modifier.isFinal(setter.getModifiers()) || Modifier.isPrivate(setter.getModifiers())) { continue; } builder.addSetter(metaBeanProperty); } } for (Constructor<?> constructor : type.getConstructors()) { if (Modifier.isPublic(constructor.getModifiers())) { builder.addConstructor(constructor); } } subclass = builder.generate(); } catch (Throwable e) { throw new GradleException( String.format("Could not generate a proxy class for class %s.", type.getName()), e); } cache.put(type, subclass); return subclass; }