private <T> CachedRuleSource doExtract(final Class<T> source) { final ModelType<T> type = ModelType.of(source); DefaultMethodModelRuleExtractionContext context = new DefaultMethodModelRuleExtractionContext(type, this); // TODO - exceptions thrown here should point to some extensive documentation on the concept of // class rule sources StructSchema<T> schema = getSchema(source, context); if (schema == null) { throw new InvalidModelRuleDeclarationException(context.problems.format()); } // sort for determinism Set<Method> methods = new TreeSet<Method>(Ordering.usingToString()); methods.addAll(Arrays.asList(source.getDeclaredMethods())); ImmutableList.Builder<ModelProperty<?>> implicitInputs = ImmutableList.builder(); ModelProperty<?> target = null; for (ModelProperty<?> property : schema.getProperties()) { if (property.isAnnotationPresent(RuleTarget.class)) { target = property; } else if (property.isAnnotationPresent(RuleInput.class) && !(property.getSchema() instanceof ScalarValueSchema)) { implicitInputs.add(property); } for (WeaklyTypeReferencingMethod<?, ?> method : property.getAccessors()) { methods.remove(method.getMethod()); } } ImmutableList.Builder<ExtractedRuleDetails> rules = ImmutableList.builder(); for (Method method : methods) { MethodRuleDefinition<?, ?> ruleDefinition = DefaultMethodRuleDefinition.create(source, method); ExtractedModelRule rule = getMethodHandler(ruleDefinition, method, context); if (rule != null) { rules.add(new ExtractedRuleDetails(ruleDefinition, rule)); } } if (context.hasProblems()) { throw new InvalidModelRuleDeclarationException(context.problems.format()); } StructBindings<T> bindings = structBindingsStore.getBindings(schema); if (schema.getProperties().isEmpty()) { return new StatelessRuleSource( rules.build(), Modifier.isAbstract(source.getModifiers()) ? new AbstractRuleSourceFactory<T>(schema, bindings, proxyFactory) : new ConcreteRuleSourceFactory<T>(type)); } else { return new ParameterizedRuleSource( rules.build(), target, implicitInputs.build(), schema, bindings, proxyFactory); } }
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; } } }