mirror of
https://github.com/querydsl/querydsl.git
synced 2026-06-21 21:14:12 +08:00
added support for factory methods in Querydsl entity query types
added more javadocs to generated Querydsl query types
This commit is contained in:
parent
7e1054be9a
commit
8fa74c3c2a
@ -1,3 +1,8 @@
|
||||
/*
|
||||
* Copyright (c) 2009 Mysema Ltd.
|
||||
* All rights reserved.
|
||||
*
|
||||
*/
|
||||
package com.mysema.query.apt;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
|
||||
@ -1,3 +1,8 @@
|
||||
/*
|
||||
* Copyright (c) 2009 Mysema Ltd.
|
||||
* All rights reserved.
|
||||
*
|
||||
*/
|
||||
package com.mysema.query.apt;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
@ -39,7 +44,8 @@ public class Configuration {
|
||||
}
|
||||
|
||||
public boolean isValidConstructor(ExecutableElement constructor) {
|
||||
return constructor.getModifiers().contains(Modifier.PUBLIC);
|
||||
return constructor.getModifiers().contains(Modifier.PUBLIC)
|
||||
&& !constructor.getParameters().isEmpty();
|
||||
}
|
||||
|
||||
public boolean isValidField(VariableElement field) {
|
||||
|
||||
@ -1,3 +1,8 @@
|
||||
/*
|
||||
* Copyright (c) 2009 Mysema Ltd.
|
||||
* All rights reserved.
|
||||
*
|
||||
*/
|
||||
package com.mysema.query.apt;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
@ -1,6 +1,16 @@
|
||||
/*
|
||||
* Copyright (c) 2009 Mysema Ltd.
|
||||
* All rights reserved.
|
||||
*
|
||||
*/
|
||||
package com.mysema.query.apt;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.annotation.processing.ProcessingEnvironment;
|
||||
import javax.lang.model.element.Element;
|
||||
@ -17,7 +27,9 @@ import org.apache.commons.lang.StringUtils;
|
||||
|
||||
import com.mysema.query.annotations.QueryType;
|
||||
import com.mysema.query.codegen.ClassModel;
|
||||
import com.mysema.query.codegen.ConstructorModel;
|
||||
import com.mysema.query.codegen.FieldModel;
|
||||
import com.mysema.query.codegen.ParameterModel;
|
||||
import com.mysema.query.codegen.TypeCategory;
|
||||
import com.mysema.query.codegen.TypeModel;
|
||||
|
||||
@ -51,7 +63,57 @@ public final class EntityElementVisitor extends SimpleElementVisitor6<ClassModel
|
||||
ClassModel classModel = new ClassModel(namePrefix, sc.getName(), c.getPackageName(), c.getName(), c.getSimpleName());
|
||||
List<? extends Element> elements = e.getEnclosedElements();
|
||||
|
||||
// CONSTRUCTORS
|
||||
|
||||
for (ExecutableElement constructor : ElementFilter.constructorsIn(elements)){
|
||||
if (configuration.isValidConstructor(constructor)){
|
||||
List<ParameterModel> parameters = new ArrayList<ParameterModel>(constructor.getParameters().size());
|
||||
for (VariableElement var : constructor.getParameters()){
|
||||
TypeModel varType = typeFactory.create(var.asType(), elementUtils);
|
||||
parameters.add(new ParameterModel(var.getSimpleName().toString(), varType.getName()));
|
||||
}
|
||||
classModel.addConstructor(new ConstructorModel(parameters));
|
||||
}
|
||||
}
|
||||
|
||||
VisitorConfig config = configuration.getConfig(e, elements);
|
||||
|
||||
Set<String> blockedFields = new HashSet<String>();
|
||||
Map<String,FieldModel> fields = new HashMap<String,FieldModel>();
|
||||
Map<String,TypeCategory> types = new HashMap<String,TypeCategory>();
|
||||
|
||||
// FIELDS
|
||||
|
||||
if (config.isVisitFields()){
|
||||
for (VariableElement field : ElementFilter.fieldsIn(elements)){
|
||||
String name = field.getSimpleName().toString();
|
||||
if (configuration.isValidField(field)){
|
||||
try{
|
||||
TypeModel typeModel = typeFactory.create(field.asType(), elementUtils);
|
||||
if (field.getAnnotation(QueryType.class) != null){
|
||||
TypeCategory typeCategory = TypeCategory.get(field.getAnnotation(QueryType.class).value());
|
||||
if (typeCategory == null){
|
||||
blockedFields.add(name);
|
||||
continue;
|
||||
}
|
||||
typeModel = typeModel.as(typeCategory);
|
||||
types.put(name, typeCategory);
|
||||
}
|
||||
fields.put(name, new FieldModel(classModel, name, typeModel, null));
|
||||
}catch(IllegalArgumentException ex){
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("Caught exception for field ");
|
||||
builder.append(c.getName()).append("#").append(field.getSimpleName());
|
||||
throw new RuntimeException(builder.toString(), ex);
|
||||
}
|
||||
|
||||
}else{
|
||||
blockedFields.add(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// METHODS
|
||||
|
||||
if (config.isVisitMethods()){
|
||||
for (ExecutableElement method : ElementFilter.methodsIn(elements)){
|
||||
@ -67,13 +129,18 @@ public final class EntityElementVisitor extends SimpleElementVisitor6<ClassModel
|
||||
try{
|
||||
TypeModel typeModel = typeFactory.create(method.getReturnType(), elementUtils);
|
||||
if (method.getAnnotation(QueryType.class) != null){
|
||||
TypeCategory category = TypeCategory.get(method.getAnnotation(QueryType.class).value());
|
||||
if (category == null){
|
||||
TypeCategory typeCategory = TypeCategory.get(method.getAnnotation(QueryType.class).value());
|
||||
if (typeCategory == null){
|
||||
blockedFields.add(name);
|
||||
continue;
|
||||
}else if (blockedFields.contains(name)){
|
||||
continue;
|
||||
}
|
||||
typeModel = typeModel.as(category);
|
||||
typeModel = typeModel.as(typeCategory);
|
||||
}else if (types.containsKey(name)){
|
||||
typeModel = typeModel.as(types.get(name));
|
||||
}
|
||||
classModel.addField(new FieldModel(classModel, name, typeModel, null));
|
||||
fields.put(name, new FieldModel(classModel, name, typeModel, null));
|
||||
|
||||
}catch(IllegalArgumentException ex){
|
||||
StringBuilder builder = new StringBuilder();
|
||||
@ -81,35 +148,18 @@ public final class EntityElementVisitor extends SimpleElementVisitor6<ClassModel
|
||||
builder.append(c.getName()).append("#").append(method.getSimpleName());
|
||||
throw new RuntimeException(builder.toString(), ex);
|
||||
}
|
||||
}
|
||||
}else{
|
||||
blockedFields.add(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (config.isVisitFields()){
|
||||
for (VariableElement field : ElementFilter.fieldsIn(elements)){
|
||||
if (configuration.isValidField(field)){
|
||||
try{
|
||||
TypeModel typeModel = typeFactory.create(field.asType(), elementUtils);
|
||||
if (field.getAnnotation(QueryType.class) != null){
|
||||
TypeCategory category = TypeCategory.get(field.getAnnotation(QueryType.class).value());
|
||||
if (category == null){
|
||||
continue;
|
||||
}
|
||||
typeModel = typeModel.as(category);
|
||||
}
|
||||
String name = field.getSimpleName().toString();
|
||||
classModel.addField(new FieldModel(classModel, name, typeModel, null));
|
||||
}catch(IllegalArgumentException ex){
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("Caught exception for field ");
|
||||
builder.append(c.getName()).append("#").append(field.getSimpleName());
|
||||
throw new RuntimeException(builder.toString(), ex);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
for (Map.Entry<String,FieldModel> entry : fields.entrySet()){
|
||||
if (!blockedFields.contains(entry.getKey())){
|
||||
classModel.addField(entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
return classModel;
|
||||
}
|
||||
|
||||
@ -35,7 +35,6 @@ import com.mysema.query.codegen.TypeModelFactory;
|
||||
* @author tiwe
|
||||
*
|
||||
*/
|
||||
// TODO : simplify this
|
||||
@Immutable
|
||||
public class Processor {
|
||||
|
||||
|
||||
@ -1,3 +1,8 @@
|
||||
/*
|
||||
* Copyright (c) 2009 Mysema Ltd.
|
||||
* All rights reserved.
|
||||
*
|
||||
*/
|
||||
package com.mysema.query.apt;
|
||||
|
||||
/**
|
||||
|
||||
@ -1,3 +1,8 @@
|
||||
/*
|
||||
* Copyright (c) 2009 Mysema Ltd.
|
||||
* All rights reserved.
|
||||
*
|
||||
*/
|
||||
package com.mysema.query.apt;
|
||||
|
||||
import javax.lang.model.type.TypeMirror;
|
||||
|
||||
@ -1,3 +1,8 @@
|
||||
/*
|
||||
* Copyright (c) 2009 Mysema Ltd.
|
||||
* All rights reserved.
|
||||
*
|
||||
*/
|
||||
package com.mysema.query.apt;
|
||||
|
||||
/**
|
||||
@ -33,5 +38,4 @@ public enum VisitorConfig {
|
||||
return methods;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -1,3 +1,8 @@
|
||||
/*
|
||||
* Copyright (c) 2009 Mysema Ltd.
|
||||
* All rights reserved.
|
||||
*
|
||||
*/
|
||||
package com.mysema.query.apt.jdo;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
|
||||
@ -1,3 +1,8 @@
|
||||
/*
|
||||
* Copyright (c) 2009 Mysema Ltd.
|
||||
* All rights reserved.
|
||||
*
|
||||
*/
|
||||
package com.mysema.query.apt.jpa;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
|
||||
@ -1,3 +1,8 @@
|
||||
/*
|
||||
* Copyright (c) 2009 Mysema Ltd.
|
||||
* All rights reserved.
|
||||
*
|
||||
*/
|
||||
package com.mysema.query.apt.jpa;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
|
||||
@ -30,7 +30,6 @@ public class ColQueryTemplates extends JavaTemplates {
|
||||
add(Ops.AOE, "{0}.compareTo({1}) >= 0");
|
||||
add(Ops.BOE, "{0}.compareTo({1}) <= 0");
|
||||
add(Ops.BETWEEN, functions + ".between({0},{1},{2})");
|
||||
// add(Ops.BETWEEN, "{0}.compareTo({1}) > 0 && {0}.compareTo({2}) < 0");
|
||||
add(Ops.STRING_CAST, "String.valueOf({0})");
|
||||
|
||||
// Date and Time
|
||||
@ -60,6 +59,7 @@ public class ColQueryTemplates extends JavaTemplates {
|
||||
}
|
||||
|
||||
public static boolean like(String str, String like){
|
||||
// TODO : better escaping
|
||||
return str.matches(like.replace("%", ".*").replace('_', '.'));
|
||||
}
|
||||
|
||||
|
||||
@ -32,11 +32,9 @@ public class Cat extends Animal {
|
||||
|
||||
private Cat mate;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@QueryType(PropertyType.NONE)
|
||||
private String skippedField;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@QueryType(PropertyType.SIMPLE)
|
||||
private String stringAsSimple;
|
||||
|
||||
@ -106,9 +104,13 @@ public class Cat extends Animal {
|
||||
this.mate = mate;
|
||||
}
|
||||
|
||||
// public String getStringAsSimple() {
|
||||
// return stringAsSimple;
|
||||
// }
|
||||
public String getStringAsSimple() {
|
||||
return stringAsSimple;
|
||||
}
|
||||
|
||||
public String getSkippedField() {
|
||||
return skippedField;
|
||||
}
|
||||
|
||||
public void setStringAsSimple(String stringAsSimple) {
|
||||
this.stringAsSimple = stringAsSimple;
|
||||
|
||||
@ -5,18 +5,31 @@
|
||||
*/
|
||||
package com.mysema.query.codegen;
|
||||
|
||||
import java.io.Writer;
|
||||
|
||||
|
||||
public class EmbeddableSerializer extends EntitySerializer{
|
||||
|
||||
@Override
|
||||
protected void introDefaultInstance(StringBuilder builder, ClassModel model) {
|
||||
// no default instance
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void constructorsForVariables(StringBuilder builder, ClassModel model) {
|
||||
// no root constructors
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void factoryMethods(ClassModel model, Writer writer) {
|
||||
// no factory methods
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void introImports(StringBuilder builder) {
|
||||
builder.append("import com.mysema.query.util.*;\n");
|
||||
builder.append("import com.mysema.query.types.path.*;\n\n");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void introDefaultInstance(StringBuilder builder, ClassModel model) {
|
||||
// no default instance
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -17,6 +17,9 @@ public class EntitySerializer implements Serializer{
|
||||
// intro
|
||||
intro(model, writer);
|
||||
|
||||
// factory methods
|
||||
factoryMethods(model, writer);
|
||||
|
||||
// fields
|
||||
for (FieldModel field : model.getStringFields()){
|
||||
stringField(field, writer);
|
||||
@ -88,6 +91,38 @@ public class EntitySerializer implements Serializer{
|
||||
outro(model, writer);
|
||||
}
|
||||
|
||||
protected void factoryMethods(ClassModel model, Writer writer) throws IOException {
|
||||
final String localName = model.getLocalName();
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (ConstructorModel c : model.getConstructors()){
|
||||
// begin
|
||||
builder.append(" /**\n");
|
||||
builder.append(" * Factory method for projection\n");
|
||||
builder.append(" */\n");
|
||||
builder.append(" public static EConstructor<" + localName + "> create(");
|
||||
boolean first = true;
|
||||
for (ParameterModel p : c.getParameters()){
|
||||
if (!first) builder.append(", ");
|
||||
builder.append("Expr<" + p.getTypeName() + "> " + p.getName());
|
||||
first = false;
|
||||
}
|
||||
builder.append("){\n");
|
||||
|
||||
// body
|
||||
builder.append(" return new EConstructor<" + localName + ">(" + localName + ".class");
|
||||
for (ParameterModel p : c.getParameters()){
|
||||
builder.append(", " + p.getName());
|
||||
}
|
||||
|
||||
// end
|
||||
builder.append(");\n");
|
||||
builder.append(" }\n\n");
|
||||
}
|
||||
writer.append(builder.toString());
|
||||
|
||||
}
|
||||
|
||||
protected void booleanField(FieldModel field, Writer writer) throws IOException {
|
||||
serialize(field, "PBoolean", writer, "createBoolean");
|
||||
}
|
||||
@ -155,6 +190,9 @@ public class EntitySerializer implements Serializer{
|
||||
final String escapedName = field.getEscapedName();
|
||||
final String queryType = field.getQueryTypeName();
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append(" /**\n");
|
||||
builder.append(" * Lazy creation of "+fieldName+" field\n");
|
||||
builder.append(" */\n");
|
||||
builder.append(" public " + queryType + " _" + fieldName + "() {\n");
|
||||
builder.append(" if (" + escapedName + " == null){\n");
|
||||
builder.append(" " + escapedName + " = new " + queryType + "(PathMetadata.forProperty(this,\"" + fieldName + "\"));\n");
|
||||
@ -180,6 +218,9 @@ public class EntitySerializer implements Serializer{
|
||||
ClassModel _super = model.getSuperModel();
|
||||
final String simpleName = _super.getSimpleName();
|
||||
final String queryType = _super.getPrefix() + simpleName;
|
||||
builder.append(" /**\n");
|
||||
builder.append(" * Reference to the same path with the supertype signature\n");
|
||||
builder.append(" */\n");
|
||||
builder.append(" public final "+queryType+" _super = new " + queryType + "(this);\n\n");
|
||||
}
|
||||
}
|
||||
@ -200,7 +241,8 @@ public class EntitySerializer implements Serializer{
|
||||
|
||||
protected void introImports(StringBuilder builder) {
|
||||
builder.append("import com.mysema.query.util.*;\n");
|
||||
builder.append("import com.mysema.query.types.path.*;\n\n");
|
||||
builder.append("import com.mysema.query.types.path.*;\n");
|
||||
builder.append("import com.mysema.query.types.expr.*;\n");
|
||||
}
|
||||
|
||||
protected void introJavadoc(StringBuilder builder, ClassModel model) {
|
||||
|
||||
@ -22,6 +22,17 @@ public class SupertypeSerializer extends EntitySerializer{
|
||||
// no default instance
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void factoryMethods(ClassModel model, Writer writer) {
|
||||
// no factory methods
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void introImports(StringBuilder builder) {
|
||||
builder.append("import com.mysema.query.util.*;\n");
|
||||
builder.append("import com.mysema.query.types.path.*;\n\n");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void constructors(ClassModel model, Writer writer) throws IOException {
|
||||
final String simpleName = model.getSimpleName();
|
||||
|
||||
@ -15,6 +15,7 @@ import java.util.regex.Pattern;
|
||||
import net.jcip.annotations.Immutable;
|
||||
|
||||
import com.mysema.query.types.Template.Element;
|
||||
import com.mysema.query.types.expr.Constant;
|
||||
import com.mysema.query.types.expr.EString;
|
||||
|
||||
/**
|
||||
@ -43,26 +44,38 @@ public class TemplateFactory {
|
||||
private final Converter<EString,EString> toStartsWithViaLike = new Converter<EString,EString>(){
|
||||
@Override
|
||||
public EString convert(EString arg) {
|
||||
return arg.append("%");
|
||||
return escapeForLike(arg).append("%");
|
||||
}
|
||||
};
|
||||
|
||||
private final Converter<EString,EString> toEndsWithViaLike = new Converter<EString,EString>(){
|
||||
@Override
|
||||
public EString convert(EString arg) {
|
||||
return arg.prepend("%");
|
||||
return escapeForLike(arg).prepend("%");
|
||||
}
|
||||
};
|
||||
|
||||
private final Converter<EString,EString> toContainsViaLike = new Converter<EString,EString>(){
|
||||
@Override
|
||||
public EString convert(EString arg) {
|
||||
return arg.prepend("%").append("%");
|
||||
return escapeForLike(arg).prepend("%").append("%");
|
||||
}
|
||||
};
|
||||
|
||||
private final Map<String,Template> cache = new HashMap<String,Template>();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private EString escapeForLike(EString expr){
|
||||
if (expr instanceof Constant){
|
||||
String str = ((Constant<String>) expr).getConstant();
|
||||
if (str.contains("%") || str.contains("_")){
|
||||
str = str.replace("%", "\\%").replace("_", "\\_");
|
||||
return EString.create(str);
|
||||
}
|
||||
}
|
||||
return expr;
|
||||
}
|
||||
|
||||
public Template create(String template){
|
||||
if (cache.containsKey(template)){
|
||||
return cache.get(template);
|
||||
|
||||
@ -59,7 +59,7 @@ public class HQLTemplates extends Templates {
|
||||
|
||||
// string
|
||||
add(Ops.CONCAT, "{0} || {1}", 37);
|
||||
add(Ops.MATCHES, "{0} like {1}", 27); // TODO : as real regex
|
||||
add(Ops.MATCHES, "{0} like {1}", 27); // TODO : support real regexes
|
||||
add(Ops.LOWER, "lower({0})");
|
||||
add(Ops.SUBSTR_1ARG, "substring({0},{1})");
|
||||
add(Ops.SUBSTR_2ARGS, "substring({0},{1},{2})");
|
||||
|
||||
Loading…
Reference in New Issue
Block a user