
org.abstractmeta.reflectify.plugin.ReflectifyGenerator Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of reflectify-protocol-codegen Show documentation
Show all versions of reflectify-protocol-codegen Show documentation
Java meta object protocol reflection code generator
The newest version!
/**
* Copyright 2011 Adrian Witas
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.abstractmeta.reflectify.plugin;
import org.abstractmeta.code.g.code.*;
import org.abstractmeta.code.g.core.code.JavaTypeImporterImpl;
import org.abstractmeta.code.g.core.code.builder.JavaConstructorBuilder;
import org.abstractmeta.code.g.core.code.builder.JavaFieldBuilder;
import org.abstractmeta.code.g.core.code.builder.JavaMethodBuilder;
import org.abstractmeta.code.g.core.code.builder.JavaTypeBuilder;
import org.abstractmeta.code.g.core.internal.ParameterizedTypeImpl;
import org.abstractmeta.code.g.core.internal.SuppressWarningsImpl;
import org.abstractmeta.code.g.core.internal.TypeNameWrapper;
import org.abstractmeta.code.g.core.internal.TypeVariableImpl;
import org.abstractmeta.code.g.core.plugin.AbstractGeneratorPlugin;
import org.abstractmeta.code.g.core.util.JavaTypeUtil;
import org.abstractmeta.code.g.core.util.ReflectUtil;
import org.abstractmeta.code.g.core.util.StringUtil;
import org.abstractmeta.code.g.config.Descriptor;
import org.abstractmeta.code.g.plugin.CodeGeneratorPlugin;
import org.abstractmeta.reflectify.*;
import org.abstractmeta.reflectify.core.AbstractType;
import org.abstractmeta.reflectify.core.AbstractMethodInvoker;
import org.abstractmeta.reflectify.core.AbstractProvider;
import org.abstractmeta.reflectify.core.AbstractReflectify;
import com.google.common.base.CaseFormat;
import com.google.common.base.Joiner;
import javax.inject.Provider;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.*;
/**
* Builder plugin.
* It creates a build class for supplied simple class plugin.
*
* @author Adrian Witas
*/
public class ReflectifyGenerator extends AbstractGeneratorPlugin implements CodeGeneratorPlugin {
private final JavaTypeImporter importer = new JavaTypeImporterImpl("");
public List generate(Collection sourceTypeNames, JavaTypeRegistry registry, Descriptor descriptor) {
List result = super.generate(sourceTypeNames, registry, descriptor);
buildProvider(result, registry, descriptor);
return result;
}
protected String getTargetTypeName(JavaType sourceType, Descriptor descriptor, JavaTypeRegistry registry) {
String buildResultTypeName = JavaTypeUtil.matchDeclaringTypeName(sourceType);
String buildResultSimpleClassName = JavaTypeUtil.getSimpleClassName(buildResultTypeName, true);
buildResultSimpleClassName = buildResultSimpleClassName.replace(".", "");
return getTargetTypeName(buildResultSimpleClassName, descriptor, registry);
}
private void buildProvider(List result, JavaTypeRegistry registry, Descriptor descriptor) {
if (result.size() == 0) {
return;
}
JavaTypeBuilder registryTypeBuilder = new JavaTypeBuilder();
registryTypeBuilder.addImportType(Arrays.class);
String targetPackage = descriptor.getTargetPackage();
if(targetPackage == null) {
targetPackage = StringUtil.substringBeforeLastIndexOf(descriptor.getSourcePackage(), ".");
}
int lastDotPosition = targetPackage.lastIndexOf('.');
int nextToLastDotPosition = targetPackage.lastIndexOf('.', lastDotPosition - 3);
String parentPackage = targetPackage.substring(nextToLastDotPosition + 1, lastDotPosition);
String providerTypeName = targetPackage + "." + StringUtil.format(CaseFormat.UPPER_CAMEL, parentPackage, "reflectifyProvider", CaseFormat.LOWER_CAMEL);
Type resultType = new ParameterizedTypeImpl(null, Collection.class, Reflectify.class);
registryTypeBuilder.addModifier("public").setTypeName(providerTypeName)
.addSuperInterface(new ParameterizedTypeImpl(null, Provider.class, resultType));
JavaMethodBuilder methodBuilder = new JavaMethodBuilder().addModifier("public")
.setName("get").setResultType(resultType);
List generatedTypes = new ArrayList();
for (String generatedType : result) {
registryTypeBuilder.addImportType(new TypeNameWrapper(generatedType));
generatedTypes.add("\n new " + JavaTypeUtil.getSimpleClassName(generatedType, true) + "()");
}
methodBuilder.addBody(String.format("return Arrays.<%s>asList(%s);", Reflectify.class.getSimpleName(), Joiner.on(",").join(generatedTypes)));
registryTypeBuilder.addMethod(methodBuilder.build());
registry.register(registryTypeBuilder.build());
result.add(registryTypeBuilder.getName());
}
@Override
protected boolean isApplicable(JavaType sourceType) {
return true;
}
@Override
protected JavaTypeBuilder generateType(JavaType sourceType, JavaTypeRegistry registry,String targetTypeName, Descriptor descriptor) {
Type reflectifyType = new TypeNameWrapper(sourceType.getName());
String classSimpleName = JavaTypeUtil.getSimpleClassName(sourceType.getName(), true);
JavaTypeBuilder protoBuilder = new JavaTypeBuilder();
protoBuilder.addModifier("public");
protoBuilder.setTypeName(targetTypeName);
protoBuilder.setSuperType(new ParameterizedTypeImpl(null, AbstractReflectify.class, reflectifyType));
protoBuilder.addConstructor(new JavaConstructorBuilder().addModifier("public").setName(protoBuilder.getSimpleName()).addBody("super(" + classSimpleName + ".class);").build());
List methods = sourceType.getMethods();
generateAccessors(protoBuilder, methods, reflectifyType);
generateMutators(protoBuilder, methods, reflectifyType);
generateMethodInvokers(protoBuilder, methods, reflectifyType);
generateProviders(protoBuilder, sourceType, reflectifyType);
if(sourceType.getName().indexOf('$') != -1) {
String innerType = sourceType.getName().replace('$', '.');
protoBuilder.addImportType(new TypeNameWrapper(innerType));
String ownerType = StringUtil.substringBeforeLastIndexOf(sourceType.getName(), "$");
protoBuilder.addImportType(new TypeNameWrapper(ownerType));
} else {
protoBuilder.addImportType(new TypeNameWrapper(sourceType.getName()));
}
return protoBuilder;
}
private void generateProviders(JavaTypeBuilder typeBuilder, JavaType sourceType, Type reflectifyType) {
Map providerCounter = new HashMap();
JavaMethodBuilder methodBuilder = new JavaMethodBuilder();
methodBuilder.addModifier("protected").setName("registerProviders").setResultType(void.class);
methodBuilder.addParameter("providers", new ParameterizedTypeImpl(null, List.class, new ParameterizedTypeImpl(null, Reflectify.Provider.class, reflectifyType)));
methodBuilder.addBody("\n");
if (sourceType.getConstructors() == null) {
return;
}
if (sourceType.getModifiers().contains("abstract")) {
return;
}
for (JavaConstructor constructor : sourceType.getConstructors()) {
String sourceTypeSimpleName = JavaTypeUtil.getSimpleClassName(sourceType.getName(), true);
String constructorCounterPostfix = getOccurrence(providerCounter, JavaTypeUtil.getSimpleClassName(sourceType.getName(), false));
String providerClassName = StringUtil.format(CaseFormat.UPPER_CAMEL, JavaTypeUtil.getSimpleClassName(sourceType.getName(), false), "provider" + constructorCounterPostfix, CaseFormat.LOWER_CAMEL);
JavaTypeBuilder providerClassBuilder = methodBuilder.addNestedJavaType();
providerClassBuilder.setName(providerClassName).addSuperInterface(
new ParameterizedTypeImpl(null, Reflectify.Provider.class, reflectifyType));
String parameters = Joiner.on(", ").join(getArgumentClasses(constructor.getParameterTypes()));
if(! parameters.isEmpty()) parameters = ", " + parameters;
providerClassBuilder.addConstructor(new JavaConstructorBuilder().setName(providerClassName).addBody(String.format("super(%s.class%s);",
sourceTypeSimpleName, parameters)).build());
providerClassBuilder.setSuperType(AbstractProvider.class);
buildArgumentSetterClasses(providerClassBuilder, reflectifyType, sourceTypeSimpleName, constructor.getParameterTypes());
methodBuilder.addBody(String.format(String.format("providers.add(new %s());", providerClassName)));
JavaMethodBuilder getMethodProvider = new JavaMethodBuilder().addModifier("public").setName("get").setResultType(reflectifyType);
String constructorParameters = Joiner.on(", ").join(getArgumentSetterMethodArgumentNames(constructor.getParameterTypes()));
boolean exceptionHandling = constructor.getExceptionTypes() != null && ! constructor.getExceptionTypes().isEmpty();
if(exceptionHandling) {
getMethodProvider.addBody("try {");
}
getMethodProvider.addBody((exceptionHandling ? " " : "") + String.format("return new %s(%s);", sourceTypeSimpleName, constructorParameters));
if(exceptionHandling) {
getMethodProvider.addBody("} catch(Exception e) {");
getMethodProvider.addBody(String.format(" throw new RuntimeException(\"Failed to instantiate %s\", e);", sourceTypeSimpleName));
getMethodProvider.addBody("}");
}
providerClassBuilder.addMethod(getMethodProvider.build());
}
typeBuilder.addMethod(methodBuilder.build());
}
protected void generateMethodInvokers(JavaTypeBuilder typeBuilder, List methods, Type reflectifyType) {
Map methodCounter = new HashMap();
JavaMethodBuilder methodBuilder = new JavaMethodBuilder();
methodBuilder.addAnnotation(new SuppressWarningsImpl("unchecked"));
methodBuilder.addModifier("protected").setName("registerMethodInvokers").setResultType(void.class);
methodBuilder.addParameter("methods", new ParameterizedTypeImpl(null, Map.class, String.class,
new ParameterizedTypeImpl(null, List.class, new ParameterizedTypeImpl(null, MethodInvoker.class, reflectifyType, Object.class))));
methodBuilder.addBody("\n");
for (JavaMethod method : methods) {
if (!method.getModifiers().contains("public")) {
continue;
}
String methodName = method.getName();
String methodInvokerTypeNamePostfix = getOccurrence(methodCounter, methodName);
String methodInvokerClassName = StringUtil.format(CaseFormat.UPPER_CAMEL, methodName, "invoker" + methodInvokerTypeNamePostfix, CaseFormat.LOWER_CAMEL);
boolean exceptionHandling = method.getExceptionTypes() != null && ! method.getExceptionTypes().isEmpty();
buildMethodInvokerType(methodBuilder, methodName, methodInvokerClassName, ReflectUtil.getObjectType(method.getResultType()), method.getParameterTypes(), reflectifyType, exceptionHandling);
methodBuilder.addBody(String.format(String.format("register(methods, \"%s\", new %s());", methodName, methodInvokerClassName)));
}
typeBuilder.addMethod(methodBuilder.build());
}
protected void buildArgumentSetterClasses(JavaTypeBuilder typeBuilder, Type reflectifyType, String name, List parameterType) {
JavaMethodBuilder parameterSetterMethod = new JavaMethodBuilder();
parameterSetterMethod.addAnnotation(new SuppressWarningsImpl("unchecked"));
parameterSetterMethod.setName("getParameterSetter").addModifier("public").addModifier("
© 2015 - 2025 Weber Informatics LLC | Privacy Policy