diff --git a/querydsl-apt/src/main/java/com/mysema/query/apt/APTModelFactory.java b/querydsl-apt/src/main/java/com/mysema/query/apt/APTModelFactory.java index 7dcdf8d03..63aca3c83 100644 --- a/querydsl-apt/src/main/java/com/mysema/query/apt/APTModelFactory.java +++ b/querydsl-apt/src/main/java/com/mysema/query/apt/APTModelFactory.java @@ -1,3 +1,8 @@ +/* + * Copyright (c) 2009 Mysema Ltd. + * All rights reserved. + * + */ package com.mysema.query.apt; import java.lang.annotation.Annotation; diff --git a/querydsl-apt/src/main/java/com/mysema/query/apt/Configuration.java b/querydsl-apt/src/main/java/com/mysema/query/apt/Configuration.java index 9f085c5c0..74e271364 100644 --- a/querydsl-apt/src/main/java/com/mysema/query/apt/Configuration.java +++ b/querydsl-apt/src/main/java/com/mysema/query/apt/Configuration.java @@ -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) { diff --git a/querydsl-apt/src/main/java/com/mysema/query/apt/DTOElementVisitor.java b/querydsl-apt/src/main/java/com/mysema/query/apt/DTOElementVisitor.java index a7b3910c7..5c86b344d 100644 --- a/querydsl-apt/src/main/java/com/mysema/query/apt/DTOElementVisitor.java +++ b/querydsl-apt/src/main/java/com/mysema/query/apt/DTOElementVisitor.java @@ -1,3 +1,8 @@ +/* + * Copyright (c) 2009 Mysema Ltd. + * All rights reserved. + * + */ package com.mysema.query.apt; import java.util.ArrayList; diff --git a/querydsl-apt/src/main/java/com/mysema/query/apt/EntityElementVisitor.java b/querydsl-apt/src/main/java/com/mysema/query/apt/EntityElementVisitor.java index 7d7ceaaec..d176d482f 100644 --- a/querydsl-apt/src/main/java/com/mysema/query/apt/EntityElementVisitor.java +++ b/querydsl-apt/src/main/java/com/mysema/query/apt/EntityElementVisitor.java @@ -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 elements = e.getEnclosedElements(); + // CONSTRUCTORS + + for (ExecutableElement constructor : ElementFilter.constructorsIn(elements)){ + if (configuration.isValidConstructor(constructor)){ + List parameters = new ArrayList(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 blockedFields = new HashSet(); + Map fields = new HashMap(); + Map types = new HashMap(); + + // 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 entry : fields.entrySet()){ + if (!blockedFields.contains(entry.getKey())){ + classModel.addField(entry.getValue()); + } + } return classModel; } diff --git a/querydsl-apt/src/main/java/com/mysema/query/apt/Processor.java b/querydsl-apt/src/main/java/com/mysema/query/apt/Processor.java index 0cd9d45b3..32c79f982 100644 --- a/querydsl-apt/src/main/java/com/mysema/query/apt/Processor.java +++ b/querydsl-apt/src/main/java/com/mysema/query/apt/Processor.java @@ -35,7 +35,6 @@ import com.mysema.query.codegen.TypeModelFactory; * @author tiwe * */ -// TODO : simplify this @Immutable public class Processor { diff --git a/querydsl-apt/src/main/java/com/mysema/query/apt/TypeArgumentsException.java b/querydsl-apt/src/main/java/com/mysema/query/apt/TypeArgumentsException.java index 7fe612baf..4e609b2be 100644 --- a/querydsl-apt/src/main/java/com/mysema/query/apt/TypeArgumentsException.java +++ b/querydsl-apt/src/main/java/com/mysema/query/apt/TypeArgumentsException.java @@ -1,3 +1,8 @@ +/* + * Copyright (c) 2009 Mysema Ltd. + * All rights reserved. + * + */ package com.mysema.query.apt; /** diff --git a/querydsl-apt/src/main/java/com/mysema/query/apt/UnsupportedTypeException.java b/querydsl-apt/src/main/java/com/mysema/query/apt/UnsupportedTypeException.java index 0eafc319e..34c2f855c 100644 --- a/querydsl-apt/src/main/java/com/mysema/query/apt/UnsupportedTypeException.java +++ b/querydsl-apt/src/main/java/com/mysema/query/apt/UnsupportedTypeException.java @@ -1,3 +1,8 @@ +/* + * Copyright (c) 2009 Mysema Ltd. + * All rights reserved. + * + */ package com.mysema.query.apt; import javax.lang.model.type.TypeMirror; diff --git a/querydsl-apt/src/main/java/com/mysema/query/apt/VisitorConfig.java b/querydsl-apt/src/main/java/com/mysema/query/apt/VisitorConfig.java index e6016bbbc..b9681e66d 100644 --- a/querydsl-apt/src/main/java/com/mysema/query/apt/VisitorConfig.java +++ b/querydsl-apt/src/main/java/com/mysema/query/apt/VisitorConfig.java @@ -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; } - } diff --git a/querydsl-apt/src/main/java/com/mysema/query/apt/jdo/JDOAnnotationProcessor.java b/querydsl-apt/src/main/java/com/mysema/query/apt/jdo/JDOAnnotationProcessor.java index c20ed1162..5ab00175f 100644 --- a/querydsl-apt/src/main/java/com/mysema/query/apt/jdo/JDOAnnotationProcessor.java +++ b/querydsl-apt/src/main/java/com/mysema/query/apt/jdo/JDOAnnotationProcessor.java @@ -1,3 +1,8 @@ +/* + * Copyright (c) 2009 Mysema Ltd. + * All rights reserved. + * + */ package com.mysema.query.apt.jdo; import java.lang.annotation.Annotation; diff --git a/querydsl-apt/src/main/java/com/mysema/query/apt/jpa/JPAAnnotationProcessor.java b/querydsl-apt/src/main/java/com/mysema/query/apt/jpa/JPAAnnotationProcessor.java index 28ff11899..5537f47f7 100644 --- a/querydsl-apt/src/main/java/com/mysema/query/apt/jpa/JPAAnnotationProcessor.java +++ b/querydsl-apt/src/main/java/com/mysema/query/apt/jpa/JPAAnnotationProcessor.java @@ -1,3 +1,8 @@ +/* + * Copyright (c) 2009 Mysema Ltd. + * All rights reserved. + * + */ package com.mysema.query.apt.jpa; import java.lang.annotation.Annotation; diff --git a/querydsl-apt/src/main/java/com/mysema/query/apt/jpa/JPAConfiguration.java b/querydsl-apt/src/main/java/com/mysema/query/apt/jpa/JPAConfiguration.java index 400000c11..00cc6769c 100644 --- a/querydsl-apt/src/main/java/com/mysema/query/apt/jpa/JPAConfiguration.java +++ b/querydsl-apt/src/main/java/com/mysema/query/apt/jpa/JPAConfiguration.java @@ -1,3 +1,8 @@ +/* + * Copyright (c) 2009 Mysema Ltd. + * All rights reserved. + * + */ package com.mysema.query.apt.jpa; import java.lang.annotation.Annotation; diff --git a/querydsl-collections/src/main/java/com/mysema/query/collections/ColQueryTemplates.java b/querydsl-collections/src/main/java/com/mysema/query/collections/ColQueryTemplates.java index be10a2e6c..d24b1ddcb 100644 --- a/querydsl-collections/src/main/java/com/mysema/query/collections/ColQueryTemplates.java +++ b/querydsl-collections/src/main/java/com/mysema/query/collections/ColQueryTemplates.java @@ -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('_', '.')); } diff --git a/querydsl-collections/src/test/java/com/mysema/query/collections/domain/Cat.java b/querydsl-collections/src/test/java/com/mysema/query/collections/domain/Cat.java index b64eb8177..ab95149a4 100644 --- a/querydsl-collections/src/test/java/com/mysema/query/collections/domain/Cat.java +++ b/querydsl-collections/src/test/java/com/mysema/query/collections/domain/Cat.java @@ -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; diff --git a/querydsl-core/src/main/java/com/mysema/query/codegen/EmbeddableSerializer.java b/querydsl-core/src/main/java/com/mysema/query/codegen/EmbeddableSerializer.java index b927acf94..e35dcf690 100644 --- a/querydsl-core/src/main/java/com/mysema/query/codegen/EmbeddableSerializer.java +++ b/querydsl-core/src/main/java/com/mysema/query/codegen/EmbeddableSerializer.java @@ -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 + } } diff --git a/querydsl-core/src/main/java/com/mysema/query/codegen/EntitySerializer.java b/querydsl-core/src/main/java/com/mysema/query/codegen/EntitySerializer.java index 8e925de44..6c57fe019 100644 --- a/querydsl-core/src/main/java/com/mysema/query/codegen/EntitySerializer.java +++ b/querydsl-core/src/main/java/com/mysema/query/codegen/EntitySerializer.java @@ -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) { diff --git a/querydsl-core/src/main/java/com/mysema/query/codegen/SupertypeSerializer.java b/querydsl-core/src/main/java/com/mysema/query/codegen/SupertypeSerializer.java index 25b3d4489..f8d760daf 100644 --- a/querydsl-core/src/main/java/com/mysema/query/codegen/SupertypeSerializer.java +++ b/querydsl-core/src/main/java/com/mysema/query/codegen/SupertypeSerializer.java @@ -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(); diff --git a/querydsl-core/src/main/java/com/mysema/query/types/TemplateFactory.java b/querydsl-core/src/main/java/com/mysema/query/types/TemplateFactory.java index 2925b06c0..63ba7b6a9 100644 --- a/querydsl-core/src/main/java/com/mysema/query/types/TemplateFactory.java +++ b/querydsl-core/src/main/java/com/mysema/query/types/TemplateFactory.java @@ -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 toStartsWithViaLike = new Converter(){ @Override public EString convert(EString arg) { - return arg.append("%"); + return escapeForLike(arg).append("%"); } }; private final Converter toEndsWithViaLike = new Converter(){ @Override public EString convert(EString arg) { - return arg.prepend("%"); + return escapeForLike(arg).prepend("%"); } }; private final Converter toContainsViaLike = new Converter(){ @Override public EString convert(EString arg) { - return arg.prepend("%").append("%"); + return escapeForLike(arg).prepend("%").append("%"); } }; private final Map cache = new HashMap(); + @SuppressWarnings("unchecked") + private EString escapeForLike(EString expr){ + if (expr instanceof Constant){ + String str = ((Constant) 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); diff --git a/querydsl-hql/src/main/java/com/mysema/query/hql/HQLTemplates.java b/querydsl-hql/src/main/java/com/mysema/query/hql/HQLTemplates.java index 427c6b97e..8f5eb1553 100644 --- a/querydsl-hql/src/main/java/com/mysema/query/hql/HQLTemplates.java +++ b/querydsl-hql/src/main/java/com/mysema/query/hql/HQLTemplates.java @@ -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})");