public <T> T createProxy( ModelElementState state, StructSchema<T> viewSchema, @Nullable StructSchema<? extends T> delegateSchema, TypeConverter typeConverter) { try { Class<? extends T> generatedClass = getGeneratedImplementation(viewSchema, delegateSchema); if (generatedClass == null) { throw new IllegalStateException( "No managed implementation class available for: " + viewSchema.getType()); } if (delegateSchema == null) { Constructor<? extends T> constructor = generatedClass.getConstructor(ModelElementState.class, TypeConverter.class); return constructor.newInstance(state, typeConverter); } else { ModelType<? extends T> delegateType = delegateSchema.getType(); Object delegate = state.getBackingNode().getPrivateData(delegateType); Constructor<? extends T> constructor = generatedClass.getConstructor( ModelElementState.class, TypeConverter.class, delegateType.getConcreteClass()); return constructor.newInstance(state, typeConverter, delegate); } } catch (InvocationTargetException e) { throw UncheckedException.throwAsUncheckedException(e.getTargetException()); } catch (Exception e) { throw UncheckedException.throwAsUncheckedException(e); } }
private void generateProxyClass( ClassWriter visitor, StructSchema<?> viewSchema, StructSchema<?> delegateSchema, Collection<String> interfacesToImplement, Set<Class<?>> typesToDelegate, Type generatedType, Type superclassType) { ModelType<?> viewType = viewSchema.getType(); Class<?> viewClass = viewType.getConcreteClass(); declareClass(visitor, interfacesToImplement, generatedType, superclassType); declareStateField(visitor); declareTypeConverterField(visitor); declareManagedTypeField(visitor); declareCanCallSettersField(visitor); writeStaticConstructor(visitor, generatedType, viewClass); writeConstructor(visitor, generatedType, superclassType, delegateSchema); writeToString(visitor, generatedType, viewClass, delegateSchema); writeManagedInstanceMethods(visitor, generatedType); if (delegateSchema != null) { declareDelegateField(visitor, delegateSchema); writeDelegateMethods(visitor, generatedType, delegateSchema, typesToDelegate); } writeGroovyMethods(visitor, viewClass); writePropertyMethods(visitor, generatedType, viewSchema, delegateSchema); writeHashCodeMethod(visitor, generatedType); writeEqualsMethod(visitor, generatedType); visitor.visitEnd(); }
@Override public T create() { Class<T> concreteClass = type.getConcreteClass(); try { Constructor<T> declaredConstructor = concreteClass.getDeclaredConstructor(); declaredConstructor.setAccessible(true); return declaredConstructor.newInstance(); } catch (InvocationTargetException e) { throw UncheckedException.throwAsUncheckedException(e.getTargetException()); } catch (Exception e) { throw UncheckedException.throwAsUncheckedException(e); } }
@Override protected <R> ModelSchema<R> createSchema( ModelSchemaExtractionContext<R> extractionContext, ModelSchemaStore store, ModelType<R> type, List<ModelProperty<?>> properties, List<ModelSchemaAspect> aspects) { return new ModelManagedImplStructSchema<R>( type, properties, aspects, type.getConcreteClass(), delegateType, Functions.<NodeInitializer>constant(null)); }
private static boolean isManagedCollection(ModelType<?> type) { Class<?> concreteClass = type.getConcreteClass(); return concreteClass.equals(ModelMap.class) || concreteClass.equals(ModelSet.class); }
/** * 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); }