Merge pull request #1662 from querydsl/p1458-querydsl3

Default variable name customization
This commit is contained in:
Timo Westkämper 2015-11-23 22:00:34 +02:00
commit eecc59ce19
17 changed files with 155 additions and 56 deletions

View File

@ -49,6 +49,8 @@ public final class APTOptions {
public static final String QUERYDSL_UNKNOWN_AS_EMBEDDABLE = "querydsl.unknownAsEmbeddable";
public static final String QUERYDSL_VARIABLE_NAME_FUNCTION_CLASS = "querydsl.variableNameFunctionClass";
private APTOptions() {}
}

View File

@ -90,7 +90,7 @@ public abstract class AbstractQuerydslProcessor extends AbstractProcessor {
Set<Class<? extends Annotation>> entityAnnotations = conf.getEntityAnnotations();
TypeMappings typeMappings = conf.getTypeMappings();
QueryTypeFactory queryTypeFactory = conf.getQueryTypeFactory();
this.typeFactory = new ExtendedTypeFactory(processingEnv, conf, entityAnnotations, typeMappings, queryTypeFactory);
this.typeFactory = new ExtendedTypeFactory(processingEnv, conf, entityAnnotations, typeMappings, queryTypeFactory, conf.getVariableNameFunction());
elementHandler = new TypeElementHandler(conf, typeFactory, typeMappings, queryTypeFactory);
this.roundEnv = roundEnv;

View File

@ -13,17 +13,19 @@
*/
package com.mysema.query.apt;
import java.lang.annotation.Annotation;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import javax.annotation.Nullable;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.TypeMirror;
import java.lang.annotation.Annotation;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import com.google.common.base.Function;
import com.mysema.query.codegen.*;
import com.mysema.util.Annotations;
@ -229,4 +231,6 @@ public interface Configuration {
*/
boolean isStrictMode();
Function<EntityType, String> getVariableNameFunction();
}

View File

@ -24,6 +24,7 @@ import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.element.*;
import javax.lang.model.type.TypeMirror;
import com.google.common.base.Function;
import com.google.common.base.Splitter;
import com.google.common.base.Strings;
import com.mysema.codegen.model.ClassType;
@ -74,6 +75,8 @@ public class DefaultConfiguration implements Configuration {
private boolean strictMode;
private Function<EntityType, String> variableNameFunction;
public DefaultConfiguration(
RoundEnvironment roundEnv,
Map<String, String> options,
@ -185,6 +188,21 @@ public class DefaultConfiguration implements Configuration {
useGetters = Boolean.valueOf(options.get(QUERYDSL_USE_GETTERS));
}
if (options.containsKey(QUERYDSL_VARIABLE_NAME_FUNCTION_CLASS)) {
try {
@SuppressWarnings("unchecked")
Class<Function<EntityType, String>> variableNameFunctionClass = (Class<Function<EntityType, String>>) Class.forName(options.get(QUERYDSL_VARIABLE_NAME_FUNCTION_CLASS));
variableNameFunction = variableNameFunctionClass.newInstance();
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
variableNameFunction = DefaultVariableNameFunction.INSTANCE;
}
} else {
variableNameFunction = DefaultVariableNameFunction.INSTANCE;
}
module.bind(CodegenModule.VARIABLE_NAME_FUNCTION_CLASS, variableNameFunction);
try {
// register additional mappings, if querydsl-spatial is on the classpath
Class.forName("com.mysema.query.spatial.GeometryExpression");
@ -475,4 +493,9 @@ public class DefaultConfiguration implements Configuration {
this.unknownAsEmbedded = unknownAsEmbedded;
}
@Override
public Function<EntityType, String> getVariableNameFunction() {
return variableNameFunction;
}
}

View File

@ -23,6 +23,7 @@ import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.*;
import com.google.common.base.Function;
import com.mysema.codegen.model.*;
import com.mysema.query.annotations.QueryExclude;
import com.mysema.query.codegen.*;
@ -53,6 +54,8 @@ public final class ExtendedTypeFactory {
private boolean doubleIndexEntities = true;
private Function<EntityType, String> variableNameFunction;
private final TypeVisitor<Type, Boolean> visitor = new SimpleTypeVisitorAdapter<Type, Boolean>() {
@Override
@ -252,7 +255,8 @@ public final class ExtendedTypeFactory {
Configuration configuration,
Set<Class<? extends Annotation>> annotations,
TypeMappings typeMappings,
QueryTypeFactory queryTypeFactory) {
QueryTypeFactory queryTypeFactory,
Function<EntityType, String> variableNameFunction) {
this.env = env;
this.defaultType = new TypeExtends(Types.OBJECT);
this.entityAnnotations = annotations;
@ -265,6 +269,7 @@ public final class ExtendedTypeFactory {
this.mapType = getErasedType(Map.class);
this.typeMappings = typeMappings;
this.queryTypeFactory = queryTypeFactory;
this.variableNameFunction = variableNameFunction;
}
private TypeMirror getErasedType(Class<?> clazz) {
@ -389,7 +394,7 @@ public final class ExtendedTypeFactory {
for (Class<? extends Annotation> entityAnn : entityAnnotations) {
if (typeElement.getAnnotation(entityAnn) != null ||
(superTypeElement != null && superTypeElement.getAnnotation(entityAnn) != null)) {
EntityType entityType = new EntityType(type);
EntityType entityType = new EntityType(type, variableNameFunction);
typeMappings.register(entityType, queryTypeFactory.create(entityType));
return entityType;
}
@ -472,7 +477,7 @@ public final class ExtendedTypeFactory {
if (value instanceof EntityType) {
entityType = (EntityType)value;
} else {
entityType = new EntityType(value);
entityType = new EntityType(value, variableNameFunction);
typeMappings.register(entityType, queryTypeFactory.create(entityType));
}
entityTypeCache.put(key, entityType);
@ -495,7 +500,7 @@ public final class ExtendedTypeFactory {
for (Class<? extends Annotation> entityAnn : entityAnnotations) {
if (typeElement.getAnnotation(entityAnn) != null) {
EntityType entityType = new EntityType(enumType);
EntityType entityType = new EntityType(enumType, variableNameFunction);
typeMappings.register(entityType, queryTypeFactory.create(entityType));
return entityType;
}

View File

@ -176,7 +176,7 @@ public final class TypeElementHandler {
public EntityType handleProjectionType(TypeElement e) {
Type c = typeFactory.getType(e.asType(), true);
EntityType entityType = new EntityType(c.as(TypeCategory.ENTITY));
EntityType entityType = new EntityType(c.as(TypeCategory.ENTITY), configuration.getVariableNameFunction());
typeMappings.register(entityType, queryTypeFactory.create(entityType));
List<? extends Element> elements = e.getEnclosedElements();
handleConstructors(entityType, elements);

View File

@ -33,6 +33,8 @@ public class CodegenModule extends AbstractModule {
public static final String IMPORTS = "imports";
public static final String VARIABLE_NAME_FUNCTION_CLASS = "variableNameFunction";
@Override
protected void configure() {
bind(TypeMappings.class, JavaTypeMappings.class);
@ -48,6 +50,7 @@ public class CodegenModule extends AbstractModule {
bind(PACKAGE_SUFFIX, "");
bind(KEYWORDS, Collections.<String>emptySet());
bind(IMPORTS, Collections.<String>emptySet());
bind(VARIABLE_NAME_FUNCTION_CLASS, DefaultVariableNameFunction.INSTANCE);
}
}

View File

@ -0,0 +1,23 @@
package com.mysema.query.codegen;
import com.google.common.base.Function;
import com.mysema.codegen.StringUtils;
import com.mysema.util.JavaSyntaxUtils;
/**
* Default variable name generation strategy which un-capitalizes the first letter of the class name.
*
*/
public final class DefaultVariableNameFunction implements Function<EntityType, String> {
public static final DefaultVariableNameFunction INSTANCE = new DefaultVariableNameFunction();
@Override
public String apply(EntityType entity) {
String uncapSimpleName = StringUtils.uncapitalize(entity.getInnerType().getSimpleName());
if (JavaSyntaxUtils.isReserved(uncapSimpleName)) {
uncapSimpleName = uncapSimpleName + "$";
}
return uncapSimpleName;
}
}

View File

@ -324,7 +324,7 @@ public class EntitySerializer implements Serializer {
}
protected void introDefaultInstance(CodeWriter writer, EntityType model, String defaultName) throws IOException {
String simpleName = !defaultName.isEmpty() ? defaultName : model.getUncapSimpleName();
String simpleName = !defaultName.isEmpty() ? defaultName : model.getModifiedSimpleName();
Type queryType = typeMappings.getPathType(model, model, true);
String alias = simpleName;
if (keywords.contains(simpleName.toUpperCase())) {

View File

@ -13,16 +13,17 @@
*/
package com.mysema.query.codegen;
import javax.annotation.Nullable;
import java.lang.annotation.Annotation;
import java.util.*;
import javax.annotation.Nullable;
import com.google.common.base.Function;
import com.mysema.codegen.StringUtils;
import com.mysema.codegen.model.Constructor;
import com.mysema.codegen.model.Type;
import com.mysema.codegen.model.TypeAdapter;
import com.mysema.codegen.model.TypeCategory;
import com.mysema.util.JavaSyntaxUtils;
/**
* EntityType represents a model of a query domain type with properties
@ -49,15 +50,25 @@ public class EntityType extends TypeAdapter implements Comparable<EntityType> {
private final Map<Object, Object> data = new HashMap<Object,Object>();
private String uncapSimpleName;
private String modifiedSimpleName;
/**
* Create a new EntityType instance for the given type
*
* @param type
*/
public EntityType(Type type) {
this(type, new LinkedHashSet<Supertype>());
this(type, new LinkedHashSet<Supertype>(), DefaultVariableNameFunction.INSTANCE);
}
/**
* Create a new {@code EntityType} instance for the given type
*
* @param type the type to be used
* @param variableNameFunction the variable name function to be used
*/
public EntityType(Type type, Function<EntityType, String> variableNameFunction) {
this(type, new LinkedHashSet<Supertype>(), variableNameFunction);
}
/**
@ -67,12 +78,20 @@ public class EntityType extends TypeAdapter implements Comparable<EntityType> {
* @param superTypes
*/
public EntityType(Type type, Set<Supertype> superTypes) {
this(type, superTypes, DefaultVariableNameFunction.INSTANCE);
}
/**
* Create a new {@code EntityType} instance for the given type and superTypes
*
* @param type the type to be used
* @param superTypes the super types to be used
* @param variableNameFunction the variable name function to be used
*/
private EntityType(Type type, Set<Supertype> superTypes, Function<EntityType, String> variableNameFunction) {
super(type);
this.uncapSimpleName = StringUtils.uncapitalize(type.getSimpleName());
if (JavaSyntaxUtils.isReserved(uncapSimpleName)) {
this.uncapSimpleName = uncapSimpleName + "$";
}
this.superTypes = superTypes;
this.modifiedSimpleName = variableNameFunction.apply(this);
}
public void addAnnotation(Annotation annotation) {
@ -171,8 +190,16 @@ public class EntityType extends TypeAdapter implements Comparable<EntityType> {
return superTypes;
}
/**
* Use {@link #getModifiedSimpleName()}
*/
@Deprecated
public String getUncapSimpleName() {
return uncapSimpleName;
return modifiedSimpleName;
}
public String getModifiedSimpleName() {
return modifiedSimpleName;
}
@Override
@ -233,10 +260,10 @@ public class EntityType extends TypeAdapter implements Comparable<EntityType> {
}
private Property validateField(Property field) {
if (field.getName().equals(uncapSimpleName) || field.getEscapedName().equals(uncapSimpleName)) {
if (field.getName().equals(modifiedSimpleName) || field.getEscapedName().equals(modifiedSimpleName)) {
do {
uncapSimpleName = StringUtils.uncapitalize(getType().getSimpleName()) + (escapeSuffix++);
} while (propertyNames.contains(uncapSimpleName));
modifiedSimpleName = StringUtils.uncapitalize(getType().getSimpleName()) + (escapeSuffix++);
} while (propertyNames.contains(modifiedSimpleName));
}
return field;
}
@ -252,4 +279,5 @@ public class EntityType extends TypeAdapter implements Comparable<EntityType> {
public Type getInnerType() {
return type;
}
}

View File

@ -21,6 +21,7 @@ import java.util.*;
import javax.annotation.Nullable;
import com.google.common.base.Function;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
@ -203,7 +204,7 @@ public class GenericExporter {
private void innerExport() {
typeMappings = codegenModule.get(TypeMappings.class);
queryTypeFactory = codegenModule.get(QueryTypeFactory.class);
typeFactory = new TypeFactory(ImmutableList.of(entityAnnotation, supertypeAnnotation, embeddableAnnotation));
typeFactory = new TypeFactory(ImmutableList.of(entityAnnotation, supertypeAnnotation, embeddableAnnotation), codegenModule.get(Function.class, CodegenModule.VARIABLE_NAME_FUNCTION_CLASS));
// copy annotations helpers to typeFactory
for (AnnotationHelper helper : annotationHelpers){

View File

@ -13,8 +13,8 @@
*/
package com.mysema.query.codegen;
import com.google.common.collect.ImmutableList;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Array;
import java.lang.reflect.TypeVariable;
import java.lang.reflect.WildcardType;
@ -23,19 +23,14 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import com.google.common.base.Function;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.common.primitives.Primitives;
import com.mysema.codegen.model.ClassType;
import com.mysema.codegen.model.SimpleType;
import com.mysema.codegen.model.Type;
import com.mysema.codegen.model.TypeCategory;
import com.mysema.codegen.model.TypeExtends;
import com.mysema.codegen.model.TypeSuper;
import com.mysema.codegen.model.Types;
import com.mysema.codegen.model.*;
import com.mysema.util.ReflectionUtils;
import java.lang.reflect.AnnotatedElement;
/**
* TypeFactory is a factory class for {@link Type} instances
@ -57,12 +52,19 @@ public final class TypeFactory {
private boolean unknownAsEntity = false;
private Function<EntityType, String> variableNameFunction;
public TypeFactory() {
this(Lists.<Class<? extends Annotation>>newArrayList());
this(Lists.<Class<? extends Annotation>>newArrayList(), DefaultVariableNameFunction.INSTANCE);
}
public TypeFactory(List<Class<? extends Annotation>> entityAnnotations) {
this(entityAnnotations, DefaultVariableNameFunction.INSTANCE);
}
public TypeFactory(List<Class<? extends Annotation>> entityAnnotations, Function<EntityType, String> variableNameFunction) {
this.entityAnnotations = entityAnnotations;
this.variableNameFunction = variableNameFunction;
}
public EntityType getEntityType(Class<?> cl) {
@ -110,7 +112,7 @@ public final class TypeFactory {
if (cache.containsKey(key)) {
Type value = cache.get(key);
if (entity && !(value instanceof EntityType)) {
value = new EntityType(value);
value = new EntityType(value, variableNameFunction);
cache.put(key, value);
}
return value;
@ -167,7 +169,7 @@ public final class TypeFactory {
}
if (entity && !(value instanceof EntityType)) {
value = new EntityType(value);
value = new EntityType(value, variableNameFunction);
}
return value;
}

View File

@ -28,28 +28,28 @@ public class EntityTypeTest {
public void UncapSimpleName_Escaped() {
ClassType typeModel = new ClassType(TypeCategory.ENTITY, Object.class);
EntityType entityModel = new EntityType(typeModel);
assertEquals("object", entityModel.getUncapSimpleName());
assertEquals("object", entityModel.getModifiedSimpleName());
entityModel.addProperty(new Property(entityModel, "object", typeModel));
assertEquals("object1", entityModel.getUncapSimpleName());
assertEquals("object1", entityModel.getModifiedSimpleName());
}
@Test
public void UncapSimpleName_Escaped2() {
ClassType typeModel = new ClassType(TypeCategory.ENTITY, Object.class);
EntityType entityModel = new EntityType(typeModel);
assertEquals("object", entityModel.getUncapSimpleName());
assertEquals("object", entityModel.getModifiedSimpleName());
entityModel.addProperty(new Property(entityModel, "OBJECT", "object", typeModel,
Collections.<String> emptyList(), false));
assertEquals("object1", entityModel.getUncapSimpleName());
assertEquals("object1", entityModel.getModifiedSimpleName());
}
@Test
public void UncapSimpleName_Escaped3() {
ClassType typeModel = new ClassType(TypeCategory.ENTITY, Void.class);
EntityType entityModel = new EntityType(typeModel);
assertEquals("void$", entityModel.getUncapSimpleName());
assertEquals("void$", entityModel.getModifiedSimpleName());
}
}

View File

@ -13,9 +13,6 @@
*/
package com.mysema.query.jpa.codegen;
import javax.annotation.Nullable;
import javax.persistence.Embeddable;
import javax.persistence.Entity;
import java.io.*;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
@ -24,6 +21,14 @@ import java.lang.reflect.Method;
import java.nio.charset.Charset;
import java.util.*;
import javax.annotation.Nullable;
import javax.persistence.Embeddable;
import javax.persistence.Entity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.base.Function;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
@ -38,8 +43,6 @@ import com.mysema.query.annotations.QueryType;
import com.mysema.query.codegen.*;
import com.mysema.util.Annotations;
import com.mysema.util.ReflectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* AbstractDomainExporter is a common supertype for DomainExporters
@ -83,6 +86,8 @@ public abstract class AbstractDomainExporter {
private final Set<File> generatedFiles = new HashSet<File>();
private final Function<EntityType, String> variableNameFunction;
/**
* @param namePrefix
* @param nameSuffix
@ -90,6 +95,7 @@ public abstract class AbstractDomainExporter {
* @param serializerConfig
* @param charset
*/
@SuppressWarnings("unchecked")
public AbstractDomainExporter(String namePrefix, String nameSuffix, File targetFolder,
SerializerConfig serializerConfig, Charset charset) {
this.targetFolder = targetFolder;
@ -104,6 +110,7 @@ public abstract class AbstractDomainExporter {
this.embeddableSerializer = module.get(EmbeddableSerializer.class);
this.entitySerializer = module.get(EntitySerializer.class);
this.supertypeSerializer = module.get(SupertypeSerializer.class);
this.variableNameFunction = module.get(Function.class, CodegenModule.VARIABLE_NAME_FUNCTION_CLASS);
}
/**
@ -202,7 +209,7 @@ public abstract class AbstractDomainExporter {
if (allTypes.containsKey(key)) {
return allTypes.get(key);
} else {
EntityType entityType = new EntityType(type);
EntityType entityType = new EntityType(type, variableNameFunction);
typeMappings.register(entityType, queryTypeFactory.create(entityType));
Class<?> superClass = key.getSuperclass();
if (entityType.getSuperType() == null && superClass != null && !superClass.equals(Object.class)) {

View File

@ -59,9 +59,9 @@ object Serializer {
def writeCompanionObject(model: EntityType, typeMappings: TypeMappings, writer: ScalaWriter) {
val queryType = typeMappings.getPathType(model, model, true)
val modelName = writer.getRawName(model)
val queryTypeName = writer.getRawName(queryType)
val variable = model.getUncapSimpleName
val queryTypeName = writer.getRawName(queryType)
val variable = model.getModifiedSimpleName
writer.beginObject(modelName + " extends "+queryTypeName+"(\""+variable+"\")")
writer.line("override def as(variable: String) = new ", queryTypeName, "(variable)")
writer.line("")

View File

@ -111,9 +111,9 @@ class ScalaEntitySerializer @Inject()(val typeMappings: TypeMappings) extends Se
}
def writeCompanionObject(model: EntityType, queryType: Type, writer: ScalaWriter) = {
val queryTypeName = writer.getRawName(queryType)
val variable = model.getUncapSimpleName
val queryTypeName = writer.getRawName(queryType)
val variable = model.getModifiedSimpleName
writer.beginObject(queryTypeName + " extends "+queryTypeName+"(\""+variable+"\")")
writer.line("override def as(variable: String) = new ", queryTypeName, "(variable)")
writer.line("")

View File

@ -27,6 +27,7 @@ import javax.annotation.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.base.Function;
import com.google.common.io.Files;
import com.mysema.codegen.CodeWriter;
import com.mysema.codegen.JavaWriter;
@ -126,7 +127,7 @@ public class MetaDataExporter {
String simpleName = module.getPrefix() + className + module.getSuffix();
Type classTypeModel = new SimpleType(TypeCategory.ENTITY,
packageName + "." + simpleName, packageName, simpleName, false, false);
classModel = new EntityType(classTypeModel);
classModel = new EntityType(classTypeModel, module.get(Function.class, CodegenModule.VARIABLE_NAME_FUNCTION_CLASS));
typeMappings.register(classModel, classModel);
} else {
@ -134,7 +135,7 @@ public class MetaDataExporter {
String simpleName = module.getBeanPrefix() + className + module.getBeanSuffix();
Type classTypeModel = new SimpleType(TypeCategory.ENTITY,
beanPackage + "." + simpleName, beanPackage, simpleName, false, false);
classModel = new EntityType(classTypeModel);
classModel = new EntityType(classTypeModel, module.get(Function.class, CodegenModule.VARIABLE_NAME_FUNCTION_CLASS));
Type mappedType = queryTypeFactory.create(classModel);
entityToWrapped.put(classModel, mappedType);