From 08726d3af34b75439efaf70c7fecc8b4c0dbf7f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Westk=C3=A4mper?= Date: Thu, 28 May 2009 11:19:15 +0000 Subject: [PATCH] --- querydsl-apt-jdk5/pom.xml | 87 ++++ querydsl-apt-jdk5/src/assembly/one-jar.xml | 27 ++ querydsl-apt-jdk5/src/assembly/plugin.xml | 25 ++ .../java/com/mysema/query/apt/APTFactory.java | 63 +++ .../java/com/mysema/query/apt/APTUtils.java | 56 +++ .../java/com/mysema/query/apt/Constants.java | 32 ++ .../query/apt/FreeMarkerSerializer.java | 47 ++ .../query/apt/general/DefaultDTOVisitor.java | 55 +++ .../apt/general/DefaultEntityVisitor.java | 96 +++++ .../mysema/query/apt/general/FieldHelper.java | 38 ++ .../query/apt/general/GeneralProcessor.java | 190 +++++++++ .../query/apt/general/QuerydslProcessor.java | 35 ++ .../mysema/query/apt/general/TypeFactory.java | 65 +++ .../mysema/query/apt/general/TypeHelper.java | 400 ++++++++++++++++++ .../query/apt/general/package-info.java | 11 + .../mysema/query/apt/jdo/JDOProcessor.java | 25 ++ .../mysema/query/apt/jpa/JPAProcessor.java | 68 +++ .../mysema/query/apt/model/Constructor.java | 27 ++ .../com/mysema/query/apt/model/Field.java | 112 +++++ .../com/mysema/query/apt/model/FieldType.java | 10 + .../com/mysema/query/apt/model/Parameter.java | 41 ++ .../java/com/mysema/query/apt/model/Type.java | 223 ++++++++++ .../com/mysema/query/apt/package-info.java | 11 + ....sun.mirror.apt.AnnotationProcessorFactory | 1 + .../resources/domain-as-outer-classes.ftl | 12 + .../main/resources/dto-as-outer-classes.ftl | 16 + .../resources/embeddable-as-outer-classes.ftl | 12 + .../src/main/resources/macros.ftl | 141 ++++++ querydsl-apt-jdk5/src/site/site.xml | 16 + .../apt/general/GeneralProcessorTest.java | 60 +++ .../query/apt/general/TypeHelperTest.java | 72 ++++ 31 files changed, 2074 insertions(+) create mode 100644 querydsl-apt-jdk5/pom.xml create mode 100644 querydsl-apt-jdk5/src/assembly/one-jar.xml create mode 100644 querydsl-apt-jdk5/src/assembly/plugin.xml create mode 100644 querydsl-apt-jdk5/src/main/java/com/mysema/query/apt/APTFactory.java create mode 100644 querydsl-apt-jdk5/src/main/java/com/mysema/query/apt/APTUtils.java create mode 100644 querydsl-apt-jdk5/src/main/java/com/mysema/query/apt/Constants.java create mode 100644 querydsl-apt-jdk5/src/main/java/com/mysema/query/apt/FreeMarkerSerializer.java create mode 100644 querydsl-apt-jdk5/src/main/java/com/mysema/query/apt/general/DefaultDTOVisitor.java create mode 100644 querydsl-apt-jdk5/src/main/java/com/mysema/query/apt/general/DefaultEntityVisitor.java create mode 100644 querydsl-apt-jdk5/src/main/java/com/mysema/query/apt/general/FieldHelper.java create mode 100644 querydsl-apt-jdk5/src/main/java/com/mysema/query/apt/general/GeneralProcessor.java create mode 100644 querydsl-apt-jdk5/src/main/java/com/mysema/query/apt/general/QuerydslProcessor.java create mode 100644 querydsl-apt-jdk5/src/main/java/com/mysema/query/apt/general/TypeFactory.java create mode 100644 querydsl-apt-jdk5/src/main/java/com/mysema/query/apt/general/TypeHelper.java create mode 100644 querydsl-apt-jdk5/src/main/java/com/mysema/query/apt/general/package-info.java create mode 100644 querydsl-apt-jdk5/src/main/java/com/mysema/query/apt/jdo/JDOProcessor.java create mode 100644 querydsl-apt-jdk5/src/main/java/com/mysema/query/apt/jpa/JPAProcessor.java create mode 100644 querydsl-apt-jdk5/src/main/java/com/mysema/query/apt/model/Constructor.java create mode 100644 querydsl-apt-jdk5/src/main/java/com/mysema/query/apt/model/Field.java create mode 100644 querydsl-apt-jdk5/src/main/java/com/mysema/query/apt/model/FieldType.java create mode 100644 querydsl-apt-jdk5/src/main/java/com/mysema/query/apt/model/Parameter.java create mode 100644 querydsl-apt-jdk5/src/main/java/com/mysema/query/apt/model/Type.java create mode 100644 querydsl-apt-jdk5/src/main/java/com/mysema/query/apt/package-info.java create mode 100644 querydsl-apt-jdk5/src/main/resources/META-INF/services/com.sun.mirror.apt.AnnotationProcessorFactory create mode 100644 querydsl-apt-jdk5/src/main/resources/domain-as-outer-classes.ftl create mode 100644 querydsl-apt-jdk5/src/main/resources/dto-as-outer-classes.ftl create mode 100644 querydsl-apt-jdk5/src/main/resources/embeddable-as-outer-classes.ftl create mode 100644 querydsl-apt-jdk5/src/main/resources/macros.ftl create mode 100644 querydsl-apt-jdk5/src/site/site.xml create mode 100644 querydsl-apt-jdk5/src/test/java/com/mysema/query/apt/general/GeneralProcessorTest.java create mode 100644 querydsl-apt-jdk5/src/test/java/com/mysema/query/apt/general/TypeHelperTest.java diff --git a/querydsl-apt-jdk5/pom.xml b/querydsl-apt-jdk5/pom.xml new file mode 100644 index 000000000..ad1228c72 --- /dev/null +++ b/querydsl-apt-jdk5/pom.xml @@ -0,0 +1,87 @@ + + + 4.0.0 + + + com.mysema.querydsl + querydsl-root + 0.3.10-SNAPSHOT + + + com.mysema.querydsl + querydsl-apt + Querydsl - APT support + source code generation for querydsl + jar + + + + org.freemarker + freemarker + 2.3.12 + + + + commons-io + commons-io + 1.4 + + + + commons-lang + commons-lang + 2.4 + + + com.mysema.querydsl + querydsl-core + ${project.parent.version} + + + + + + + + maven-assembly-plugin + + + src/assembly/one-jar.xml + + + + + make-assembly + package + + attached + + + + + + + + + + default-tools.jar + + + java.vendor + Sun Microsystems Inc. + + + + + com.sun + tools + 1.4.2 + system + ${java.home}/../lib/tools.jar + + + + + + \ No newline at end of file diff --git a/querydsl-apt-jdk5/src/assembly/one-jar.xml b/querydsl-apt-jdk5/src/assembly/one-jar.xml new file mode 100644 index 000000000..632742931 --- /dev/null +++ b/querydsl-apt-jdk5/src/assembly/one-jar.xml @@ -0,0 +1,27 @@ + + one-jar + + jar + + false + + + + true + + + + + + target/classes + + + + \ No newline at end of file diff --git a/querydsl-apt-jdk5/src/assembly/plugin.xml b/querydsl-apt-jdk5/src/assembly/plugin.xml new file mode 100644 index 000000000..7ae891d91 --- /dev/null +++ b/querydsl-apt-jdk5/src/assembly/plugin.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/querydsl-apt-jdk5/src/main/java/com/mysema/query/apt/APTFactory.java b/querydsl-apt-jdk5/src/main/java/com/mysema/query/apt/APTFactory.java new file mode 100644 index 000000000..42bbc2404 --- /dev/null +++ b/querydsl-apt-jdk5/src/main/java/com/mysema/query/apt/APTFactory.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2008 Mysema Ltd. + * All rights reserved. + * + */ +package com.mysema.query.apt; + +import static com.mysema.query.apt.Constants.*; + +import static com.mysema.query.apt.APTUtils.getString; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Set; + +import com.mysema.query.apt.general.QuerydslProcessor; +import com.mysema.query.apt.jdo.JDOProcessor; +import com.mysema.query.apt.jpa.JPAProcessor; +import com.sun.mirror.apt.AnnotationProcessor; +import com.sun.mirror.apt.AnnotationProcessorEnvironment; +import com.sun.mirror.apt.AnnotationProcessorFactory; +import com.sun.mirror.declaration.AnnotationTypeDeclaration; + +/** + * APTFactory is the main APT factory for Querydsl code generation + * + * @author tiwe + * @version $Id$ + */ +public class APTFactory implements AnnotationProcessorFactory { + + private static final Collection supportedAnnotations = Arrays + .asList(QD_ENTITY, QD_DTO, JDO_ENTITY, JPA_ENTITY, JPA_SUPERCLASS, + JPA_EMBEDDABLE); + + private static final Collection supportedOptions = Collections + .emptySet(); + + public Collection supportedAnnotationTypes() { + return supportedAnnotations; + } + + public Collection supportedOptions() { + return supportedOptions; + } + + public AnnotationProcessor getProcessorFor( + Set atds, + AnnotationProcessorEnvironment env) { + String profile = getString(env.getOptions(), "profile", "jpa"); + if ("jpa".equals(profile)) { + return new JPAProcessor(env); + } else if ("jdo".equals(profile)) { + return new JDOProcessor(env); + } else if ("querydsl".equals(profile)) { + return new QuerydslProcessor(env); + } else { + throw new IllegalArgumentException("Unknown profile " + profile); + } + } + +} \ No newline at end of file diff --git a/querydsl-apt-jdk5/src/main/java/com/mysema/query/apt/APTUtils.java b/querydsl-apt-jdk5/src/main/java/com/mysema/query/apt/APTUtils.java new file mode 100644 index 000000000..168524b93 --- /dev/null +++ b/querydsl-apt-jdk5/src/main/java/com/mysema/query/apt/APTUtils.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2008 Mysema Ltd. + * All rights reserved. + * + */ +package com.mysema.query.apt; + +import java.io.*; +import java.util.Map; + +import org.apache.commons.io.FileUtils; + +/** + * APUtils provides utilities for APT code generation in Querydsl + * + * @author tiwe + * @version $Id$ + */ +public class APTUtils { + + public static Writer writerFor(File file) { + if (!file.getParentFile().exists() && !file.getParentFile().mkdirs()) { + System.err.println("Folder " + file.getParent() + + " could not be created"); + } + try { + return new OutputStreamWriter(new FileOutputStream(file)); + } catch (FileNotFoundException e) { + throw new RuntimeException(e.getMessage(), e); + } + } + + public static String getFileContent(Map options, + String key, String defaultValue) throws IOException { + String path = getString(options, key, null); + if (path != null) { + return FileUtils.readFileToString(new File(path), "UTF-8"); + } else { + return ""; + } + } + + public static String getString(Map options, String key, + String defaultValue) { + String prefix = "-A" + key + "="; + for (Map.Entry entry : options.entrySet()) { + if (entry.getKey().startsWith(prefix)) { + return entry.getKey().substring(prefix.length()); + } else if (entry.getKey().equals(key)) { + return entry.getValue(); + } + } + return defaultValue; + } + +} diff --git a/querydsl-apt-jdk5/src/main/java/com/mysema/query/apt/Constants.java b/querydsl-apt-jdk5/src/main/java/com/mysema/query/apt/Constants.java new file mode 100644 index 000000000..40a098a45 --- /dev/null +++ b/querydsl-apt-jdk5/src/main/java/com/mysema/query/apt/Constants.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2009 Mysema Ltd. + * All rights reserved. + * + */ +package com.mysema.query.apt; + +import com.mysema.query.annotations.DTO; +import com.mysema.query.annotations.Entity; + +/** + * Constants provides constants for use in Querydsl APT + * + * @author tiwe + * @version $Id$ + */ +public final class Constants { + private Constants() { + } + + public static final String QD_ENTITY = Entity.class.getName(); + public static final String QD_DTO = DTO.class.getName(); + + // JDO + public static final String JDO_ENTITY = "javax.jdo.annotations.PersistenceCapable"; + + // JPA + public static final String JPA_SUPERCLASS = "javax.persistence.MappedSuperclass"; + public static final String JPA_ENTITY = "javax.persistence.Entity"; + public static final String JPA_EMBEDDABLE = "javax.persistence.Embeddable"; + +} diff --git a/querydsl-apt-jdk5/src/main/java/com/mysema/query/apt/FreeMarkerSerializer.java b/querydsl-apt-jdk5/src/main/java/com/mysema/query/apt/FreeMarkerSerializer.java new file mode 100644 index 000000000..0536f7327 --- /dev/null +++ b/querydsl-apt-jdk5/src/main/java/com/mysema/query/apt/FreeMarkerSerializer.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2008 Mysema Ltd. + * All rights reserved. + * + */ +package com.mysema.query.apt; + +import java.io.IOException; +import java.io.Writer; +import java.util.Map; + +import freemarker.template.Configuration; +import freemarker.template.DefaultObjectWrapper; +import freemarker.template.TemplateException; + +/** + * FreeMarkerSerializer provides FreeMarker based serialization of querydsl + * types to Java sources + * + * @author tiwe + * @version $Id$ + */ +public class FreeMarkerSerializer { + + private static final Configuration cfg; + + static { + cfg = new Configuration(); + cfg.setClassForTemplateLoading(FreeMarkerSerializer.class, "/"); + cfg.setObjectWrapper(new DefaultObjectWrapper()); + } + + private final String templateLocation; + + public FreeMarkerSerializer(String template) { + if (template == null) + throw new IllegalArgumentException("template was null"); + templateLocation = template; + } + + public void serialize(Map model, Writer writer) + throws IOException, TemplateException { + cfg.getTemplate(templateLocation).process(model, writer); + writer.flush(); + } + +} diff --git a/querydsl-apt-jdk5/src/main/java/com/mysema/query/apt/general/DefaultDTOVisitor.java b/querydsl-apt-jdk5/src/main/java/com/mysema/query/apt/general/DefaultDTOVisitor.java new file mode 100644 index 000000000..901773017 --- /dev/null +++ b/querydsl-apt-jdk5/src/main/java/com/mysema/query/apt/general/DefaultDTOVisitor.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2009 Mysema Ltd. + * All rights reserved. + * + */ +package com.mysema.query.apt.general; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.TreeSet; + +import com.mysema.query.apt.model.Constructor; +import com.mysema.query.apt.model.Parameter; +import com.mysema.query.apt.model.Type; +import com.sun.mirror.declaration.ClassDeclaration; +import com.sun.mirror.declaration.ConstructorDeclaration; +import com.sun.mirror.declaration.ParameterDeclaration; +import com.sun.mirror.util.SimpleDeclarationVisitor; + +/** + * DTOVisitor is a visitor for DTO types. + * + * @author tiwe + * @version $Id$ + */ +public class DefaultDTOVisitor extends SimpleDeclarationVisitor { + final Set types = new TreeSet(); + + private Type last; + + @Override + public void visitClassDeclaration(ClassDeclaration d) { + String simpleName = d.getSimpleName(); + String name = d.getQualifiedName(); + String packageName = d.getPackage().getQualifiedName(); + String superType = d.getSuperclass().getDeclaration() + .getQualifiedName(); + last = new Type(superType, packageName, name, simpleName); + types.add(last); + } + + @Override + public void visitConstructorDeclaration(ConstructorDeclaration d) { + List parameters = new ArrayList(d.getParameters() + .size()); + for (ParameterDeclaration pa : d.getParameters()) { + String name = pa.getSimpleName(); + String typeName = new TypeHelper(pa.getType()).getFullName(); + parameters.add(new Parameter(name, typeName)); + } + last.addConstructor(new Constructor(parameters)); + } + +} diff --git a/querydsl-apt-jdk5/src/main/java/com/mysema/query/apt/general/DefaultEntityVisitor.java b/querydsl-apt-jdk5/src/main/java/com/mysema/query/apt/general/DefaultEntityVisitor.java new file mode 100644 index 000000000..0e590894b --- /dev/null +++ b/querydsl-apt-jdk5/src/main/java/com/mysema/query/apt/general/DefaultEntityVisitor.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2009 Mysema Ltd. + * All rights reserved. + * + */ +package com.mysema.query.apt.general; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.commons.lang.StringUtils; + +import com.mysema.query.apt.model.Field; +import com.mysema.query.apt.model.FieldType; +import com.mysema.query.apt.model.Type; +import com.sun.mirror.declaration.ClassDeclaration; +import com.sun.mirror.declaration.FieldDeclaration; +import com.sun.mirror.declaration.InterfaceDeclaration; +import com.sun.mirror.declaration.MethodDeclaration; +import com.sun.mirror.declaration.Modifier; +import com.sun.mirror.util.SimpleDeclarationVisitor; + +/** + * DefaultEntityVisitor is a visitor for entity and embeddable types. + * + * @author tiwe + * @version $Id$ + */ +public class DefaultEntityVisitor extends SimpleDeclarationVisitor { + private Type last; + + public final Map types = new HashMap(); + + private void addField(String originalName, TypeHelper typeInfo) { + String name = FieldHelper.javaSafe(originalName); + String realName = FieldHelper.realName(originalName); + String keyTypeName = typeInfo.getKeyTypeName(); + String typeName = typeInfo.getFullName(); + String typePackage = typeInfo.getPackageName(); + String simpleTypeName = typeInfo.getSimpleName(); + FieldType fieldType = typeInfo.getFieldType(); + last.addField(new Field(name, realName, keyTypeName, typePackage, + typeName, simpleTypeName, fieldType)); + } + + @Override + public void visitClassDeclaration(ClassDeclaration d) { + String simpleName = d.getSimpleName(); + String name = d.getQualifiedName(); + String packageName = d.getPackage().getQualifiedName(); + String superType = d.getSuperclass().getDeclaration() + .getQualifiedName(); + last = new Type(superType, packageName, name, simpleName); + types.put(d.getQualifiedName(), last); + } + + @Override + public void visitFieldDeclaration(FieldDeclaration d) { + if (!d.getModifiers().contains(Modifier.STATIC) + && !d.getModifiers().contains(Modifier.TRANSIENT)) { + addField(d.getSimpleName(), new TypeHelper(d.getType())); + } + } + + @Override + public void visitInterfaceDeclaration(InterfaceDeclaration d) { + String simpleName = d.getSimpleName(); + String name = d.getQualifiedName(); + String packageName = d.getPackage().getQualifiedName(); + String superType = null; + if (!d.getSuperinterfaces().isEmpty()) { + superType = d.getSuperinterfaces().iterator().next() + .getDeclaration().getQualifiedName(); + } + last = new Type(superType, packageName, name, simpleName); + types.put(d.getQualifiedName(), last); + } + + @Override + public void visitMethodDeclaration(MethodDeclaration d) { + if (!d.getModifiers().contains(Modifier.STATIC)) { + if (d.getParameters().isEmpty()) { + if (d.getSimpleName().startsWith("get")) { + String name = StringUtils.uncapitalize(d.getSimpleName() + .substring(3)); + addField(name, new TypeHelper(d.getReturnType())); + } else if (d.getSimpleName().startsWith("is")) { + String name = StringUtils.uncapitalize(d.getSimpleName() + .substring(2)); + addField(name, new TypeHelper(d.getReturnType())); + } + } + } + } + +} \ No newline at end of file diff --git a/querydsl-apt-jdk5/src/main/java/com/mysema/query/apt/general/FieldHelper.java b/querydsl-apt-jdk5/src/main/java/com/mysema/query/apt/general/FieldHelper.java new file mode 100644 index 000000000..e490efc76 --- /dev/null +++ b/querydsl-apt-jdk5/src/main/java/com/mysema/query/apt/general/FieldHelper.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2009 Mysema Ltd. + * All rights reserved. + * + */ +package com.mysema.query.apt.general; + +/** + * FieldHelper provides convenience methods for field name escaping + * + * @author tiwe + * @version $Id$ + */ +public class FieldHelper { + + public static String javaSafe(String name) { + // TODO : improve this + if (name.equals("private")) { + return "prvate"; + } else if (name.equals("public")) { + return "pblic"; + } else { + return name; + } + } + + public static String realName(String name) { + // TODO : improve this + if (name.equals("prvate")) { + return "private"; + } else if (name.equals("pblic")) { + return "public"; + } else { + return name; + } + } + +} diff --git a/querydsl-apt-jdk5/src/main/java/com/mysema/query/apt/general/GeneralProcessor.java b/querydsl-apt-jdk5/src/main/java/com/mysema/query/apt/general/GeneralProcessor.java new file mode 100644 index 000000000..63a1d526f --- /dev/null +++ b/querydsl-apt-jdk5/src/main/java/com/mysema/query/apt/general/GeneralProcessor.java @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2009 Mysema Ltd. + * All rights reserved. + * + */ +package com.mysema.query.apt.general; + +import static com.mysema.query.apt.APTUtils.getString; +import static com.mysema.query.apt.APTUtils.writerFor; +import static com.sun.mirror.util.DeclarationVisitors.NO_OP; +import static com.sun.mirror.util.DeclarationVisitors.getDeclarationScanner; + +import java.io.File; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +import com.mysema.query.apt.FreeMarkerSerializer; +import com.mysema.query.apt.model.Type; +import com.sun.mirror.apt.AnnotationProcessor; +import com.sun.mirror.apt.AnnotationProcessorEnvironment; +import com.sun.mirror.declaration.AnnotationTypeDeclaration; +import com.sun.mirror.declaration.Declaration; + +/** + * GeneralProcessor is the main processor for APT code generation. + * + * @author tiwe + * @version $Id$ + */ +public abstract class GeneralProcessor implements AnnotationProcessor { + + public static final FreeMarkerSerializer DOMAIN_OUTER_TMPL = new FreeMarkerSerializer( + "/domain-as-outer-classes.ftl"), + EMBEDDABLE_OUTER_TMPL = new FreeMarkerSerializer( + "/embeddable-as-outer-classes.ftl"), + DTO_OUTER_TMPL = new FreeMarkerSerializer( + "/dto-as-outer-classes.ftl"); + + protected final String namePrefix, targetFolder; + + protected final AnnotationProcessorEnvironment env; + + protected final String superClassAnnotation, domainAnnotation, + dtoAnnotation; + + public GeneralProcessor(AnnotationProcessorEnvironment env, + String superClassAnnotation, String domainAnnotation, + String dtoAnnotation) { + this.env = env; + this.targetFolder = env.getOptions().get("-s"); + this.namePrefix = getString(env.getOptions(), "namePrefix", "Q"); + + this.superClassAnnotation = superClassAnnotation; + this.domainAnnotation = domainAnnotation; + this.dtoAnnotation = dtoAnnotation; + } + + private void addSupertypeFields(Type typeDecl, + Map entityTypes, Map mappedSupertypes) { + String stype = typeDecl.getSupertypeName(); + Class superClass = safeClassForName(stype); + if (entityTypes.containsKey(stype) + || mappedSupertypes.containsKey(stype)) { + while (true) { + Type sdecl; + if (entityTypes.containsKey(stype)) { + sdecl = entityTypes.get(stype); + } else if (mappedSupertypes.containsKey(stype)) { + sdecl = mappedSupertypes.get(stype); + } else { + return; + } + typeDecl.include(sdecl); + stype = sdecl.getSupertypeName(); + } + + } else if (superClass != null && !superClass.equals(Object.class)) { + // TODO : recursively up ? + Type type = TypeFactory.createType(superClass); + // include fields of supertype + typeDecl.include(type); + } + } + + private Class safeClassForName(String stype) { + try { + return stype != null ? Class.forName(stype) : null; + } catch (ClassNotFoundException e) { + return null; + } + } + + protected DefaultEntityVisitor createEntityVisitor() { + return new DefaultEntityVisitor(); + } + + protected DefaultDTOVisitor createDTOVisitor() { + return new DefaultDTOVisitor(); + } + + private void createDomainClasses() { + DefaultEntityVisitor superclassVisitor = createEntityVisitor(); + + // mapped superclass + AnnotationTypeDeclaration a; + Map mappedSupertypes; + if (superClassAnnotation != null) { + a = (AnnotationTypeDeclaration) env + .getTypeDeclaration(superClassAnnotation); + for (Declaration typeDecl : env.getDeclarationsAnnotatedWith(a)) { + typeDecl + .accept(getDeclarationScanner(superclassVisitor, NO_OP)); + } + mappedSupertypes = superclassVisitor.types; + } else { + mappedSupertypes = new HashMap(); + } + + // domain types + DefaultEntityVisitor entityVisitor = createEntityVisitor(); + a = (AnnotationTypeDeclaration) env + .getTypeDeclaration(domainAnnotation); + for (Declaration typeDecl : env.getDeclarationsAnnotatedWith(a)) { + typeDecl.accept(getDeclarationScanner(entityVisitor, NO_OP)); + } + Map entityTypes = entityVisitor.types; + + for (Type typeDecl : entityTypes.values()) { + addSupertypeFields(typeDecl, entityTypes, mappedSupertypes); + } + + if (entityTypes.isEmpty()) { + env.getMessager().printNotice( + "No class generation for domain types"); + } else { + serializeAsOuterClasses(entityTypes.values(), DOMAIN_OUTER_TMPL); + } + + } + + private void createDTOClasses() { + AnnotationTypeDeclaration a = (AnnotationTypeDeclaration) env + .getTypeDeclaration(dtoAnnotation); + DefaultDTOVisitor dtoVisitor = createDTOVisitor(); + for (Declaration typeDecl : env.getDeclarationsAnnotatedWith(a)) { + typeDecl.accept(getDeclarationScanner(dtoVisitor, NO_OP)); + } + if (dtoVisitor.types.isEmpty()) { + env.getMessager().printNotice("No class generation for DTO types"); + } else { + serializeAsOuterClasses(dtoVisitor.types, DTO_OUTER_TMPL); + } + + } + + public void process() { + if (domainAnnotation != null) { + createDomainClasses(); + } + if (dtoAnnotation != null) { + createDTOClasses(); + } + } + + protected void serializeAsOuterClasses(Collection entityTypes, + FreeMarkerSerializer serializer) { + // populate model + Map model = new HashMap(); + model.put("pre", namePrefix); + + for (Type type : entityTypes) { + String packageName = type.getPackageName(); + model.put("package", packageName); + model.put("type", type); + model.put("classSimpleName", type.getSimpleName()); + + // serialize it + try { + String path = packageName.replace('.', '/') + "/" + namePrefix + + type.getSimpleName() + ".java"; + serializer.serialize(model, writerFor(new File(targetFolder, + path))); + } catch (Exception e) { + throw new RuntimeException(e.getMessage(), e); + } + } + } + +} diff --git a/querydsl-apt-jdk5/src/main/java/com/mysema/query/apt/general/QuerydslProcessor.java b/querydsl-apt-jdk5/src/main/java/com/mysema/query/apt/general/QuerydslProcessor.java new file mode 100644 index 000000000..bc9430d32 --- /dev/null +++ b/querydsl-apt-jdk5/src/main/java/com/mysema/query/apt/general/QuerydslProcessor.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2009 Mysema Ltd. + * All rights reserved. + * + */ +package com.mysema.query.apt.general; + +import static com.mysema.query.apt.Constants.*; + +import com.sun.mirror.apt.AnnotationProcessorEnvironment; +import com.sun.mirror.declaration.MethodDeclaration; + +/** + * QureydslProcessor provides Querydsl annotation handling support + * + * @author tiwe + * @version $Id$ + */ +public class QuerydslProcessor extends GeneralProcessor { + + public QuerydslProcessor(AnnotationProcessorEnvironment env) { + super(env, null, QD_ENTITY, QD_DTO); + } + + @Override + protected DefaultEntityVisitor createEntityVisitor() { + return new DefaultEntityVisitor() { + @Override + public void visitMethodDeclaration(MethodDeclaration d) { + // skip property handling + } + }; + } + +} diff --git a/querydsl-apt-jdk5/src/main/java/com/mysema/query/apt/general/TypeFactory.java b/querydsl-apt-jdk5/src/main/java/com/mysema/query/apt/general/TypeFactory.java new file mode 100644 index 000000000..2f9d16ad5 --- /dev/null +++ b/querydsl-apt-jdk5/src/main/java/com/mysema/query/apt/general/TypeFactory.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2009 Mysema Ltd. + * All rights reserved. + * + */ +package com.mysema.query.apt.general; + +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.TypeVariable; +import java.lang.reflect.WildcardType; + +import com.mysema.query.apt.model.Field; +import com.mysema.query.apt.model.Type; + +/** + * TypeFactory provides + * + * @author tiwe + * @version $Id$ + */ +public class TypeFactory { + + public static Type createType(Class clazz) { + Type type = new Type(clazz.getSuperclass().getName(), clazz + .getPackage().getName(), clazz.getName(), clazz.getSimpleName()); + for (java.lang.reflect.Field f : clazz.getDeclaredFields()) { + TypeHelper typeHelper = new TypeHelper(f.getType(), f + .getGenericType()); + Field field = new Field( + FieldHelper.javaSafe(f.getName()), // name + FieldHelper.realName(f.getName()), // realName + typeHelper.getKeyTypeName(), typeHelper.getPackageName(), + typeHelper.getFullName(), typeHelper.getSimpleName(), + typeHelper.getFieldType()); + type.addField(field); + } + return type; + } + + // TODO : move this to common place + public static Class getTypeParameter(java.lang.reflect.Type type, + int index) { + if (type instanceof ParameterizedType) { + ParameterizedType ptype = (ParameterizedType) type; + java.lang.reflect.Type[] targs = ptype.getActualTypeArguments(); + if (targs[index] instanceof WildcardType) { + WildcardType wildcardType = (WildcardType) targs[index]; + return (Class) wildcardType.getUpperBounds()[0]; + } else if (targs[index] instanceof TypeVariable) { + return (Class) ((TypeVariable) targs[index]) + .getGenericDeclaration(); + } else if (targs[index] instanceof ParameterizedType) { + return (Class) ((ParameterizedType) targs[index]) + .getRawType(); + } else { + try { + return (Class) targs[index]; + } catch (Exception e) { + e.printStackTrace(); + } + } + } + return null; + } +} diff --git a/querydsl-apt-jdk5/src/main/java/com/mysema/query/apt/general/TypeHelper.java b/querydsl-apt-jdk5/src/main/java/com/mysema/query/apt/general/TypeHelper.java new file mode 100644 index 000000000..3c0971cff --- /dev/null +++ b/querydsl-apt-jdk5/src/main/java/com/mysema/query/apt/general/TypeHelper.java @@ -0,0 +1,400 @@ +/* + * Copyright (c) 2009 Mysema Ltd. + * All rights reserved. + * + */ +package com.mysema.query.apt.general; + +import java.lang.reflect.Type; +import java.util.Iterator; +import java.util.Locale; + +import org.apache.commons.lang.ClassUtils; + +import com.mysema.query.annotations.Literal; +import com.mysema.query.apt.model.FieldType; +import com.sun.mirror.type.*; +import com.sun.mirror.util.SimpleTypeVisitor; + +/** + * TypeInfo is a helper type for determing types of fields and methods + * + * @author tiwe + * @version $Id$ + */ +// TODO : clean this up +public class TypeHelper extends SimpleTypeVisitor { + + private FieldType fieldType; + + private String simpleName, fullName, packageName = "", keyTypeName; + + public TypeHelper(Class cl) { + this(cl, cl); + } + + public TypeHelper(Class cl, Type genericType) { + if (cl == null) { + throw new IllegalArgumentException("cl was null"); + } else if (cl.isArray()) { + visitArrayType(cl); + } else if (cl.isEnum()) { + visitEnumType(cl); + } else if (cl.isPrimitive()) { + visitPrimitiveType(cl); + } else if (cl.isInterface()) { + visitInterfaceType(cl, genericType); + } else { + visitClassType(cl); + } + if (fullName == null) { + fullName = cl.getName(); + } + + setDefaults(); + } + + public TypeHelper(TypeMirror type) { + type.accept(this); + if (fullName == null) { + fullName = type.toString(); + } + setDefaults(); + } + + public FieldType getFieldType() { + return fieldType; + } + + public String getFullName() { + return fullName; + } + + public String getKeyTypeName() { + return keyTypeName; + } + + public String getPackageName() { + return packageName; + } + + public String getSimpleName() { + return simpleName; + } + + public String getValueTypeName() { + return fullName; + } + + private void handleCollectionInterface(Class type, Type genericType) { + TypeHelper valueInfo = new TypeHelper(TypeFactory.getTypeParameter( + genericType, 0)); + handleCollection(valueInfo); + } + + private void handleCollectionInterface(Iterator i) { + TypeHelper valueInfo = new TypeHelper(i.next()); + handleCollection(valueInfo); + } + + private void handleCollection(TypeHelper valueInfo) { + fullName = valueInfo.getFullName(); + packageName = valueInfo.getPackageName(); + if (valueInfo.fieldType == FieldType.ENTITY) { + fieldType = FieldType.ENTITYCOLLECTION; + } else { + fieldType = FieldType.SIMPLECOLLECTION; + } + } + + private void handleList(Iterator i) { + TypeHelper valueInfo = new TypeHelper(i.next()); + handleList(valueInfo); + } + + private void handleList(TypeHelper valueInfo) { + fullName = valueInfo.getFullName(); + packageName = valueInfo.getPackageName(); + if (valueInfo.fieldType == FieldType.ENTITY) { + fieldType = FieldType.ENTITYLIST; + } else { + fieldType = FieldType.SIMPLELIST; + } + } + + private void handleListInterface(Class type, Type genericType) { + TypeHelper valueInfo = new TypeHelper(TypeFactory.getTypeParameter( + genericType, 0)); + handleList(valueInfo); + } + + private void handleMapInterface(Class type, Type genericType) { + TypeHelper keyInfo = new TypeHelper(TypeFactory.getTypeParameter( + genericType, 0)); + TypeHelper valueInfo = new TypeHelper(TypeFactory.getTypeParameter( + genericType, 1)); + handleMapInterface(keyInfo, valueInfo); + } + + private void handleMapInterface(Iterator i) { + TypeHelper keyInfo = new TypeHelper(i.next()); + TypeHelper valueInfo = new TypeHelper(i.next()); + handleMapInterface(keyInfo, valueInfo); + } + + private void handleMapInterface(TypeHelper keyInfo, TypeHelper valueInfo) { + keyTypeName = keyInfo.getFullName(); + fullName = valueInfo.getFullName(); + packageName = valueInfo.getPackageName(); + if (valueInfo.fieldType == FieldType.ENTITY) { + fieldType = FieldType.ENTITYMAP; + } else { + fieldType = FieldType.SIMPLEMAP; + } + } + + private void setDefaults() { + if (fieldType == null) { + fieldType = FieldType.ENTITY; + } + if (simpleName == null) { + simpleName = fullName.substring(fullName.lastIndexOf('.') + 1); + } + } + + public String toString() { + return fullName; + } + + @Override + public void visitAnnotationType(AnnotationType arg0) { + // + } + + private void visitArrayComponentType(TypeHelper valueInfo) { + fullName = valueInfo.getFullName(); + packageName = valueInfo.getPackageName(); + if (valueInfo.fieldType == FieldType.ENTITY) { + fieldType = FieldType.ENTITYCOLLECTION; + } else { + fieldType = FieldType.SIMPLECOLLECTION; + } + } + + @Override + public void visitArrayType(ArrayType arg0) { + TypeHelper valueInfo = new TypeHelper(arg0.getComponentType()); + visitArrayComponentType(valueInfo); + } + + public void visitArrayType(Class clazz) { + TypeHelper valueInfo = new TypeHelper(clazz.getComponentType()); + visitArrayComponentType(valueInfo); + } + + public void visitClassType(Class type) { + fullName = type.getName(); + packageName = type.getPackage().getName(); + + if (type.equals(String.class)) { + fieldType = FieldType.STRING; + + } else if (type.equals(Boolean.class)) { + fieldType = FieldType.BOOLEAN; + + } else if (type.equals(Locale.class) || type.equals(Class.class) + || type.equals(Object.class)) { + fieldType = FieldType.SIMPLE; + + } else if (isNumericSupported(fullName) + && Number.class.isAssignableFrom(type)) { + fieldType = FieldType.NUMERIC; + + } else if (type.getAnnotation(Literal.class) != null) { + if (Comparable.class.isAssignableFrom(type)) { + fieldType = FieldType.COMPARABLE; + } else { + fieldType = FieldType.SIMPLE; + } + + } else if (isComparableSupported(fullName) + && Comparable.class.isAssignableFrom(type)) { + fieldType = FieldType.COMPARABLE; + + } else if (asSimpleType(fullName)) { + fieldType = FieldType.SIMPLE; + + } + } + + @Override + public void visitClassType(ClassType arg0) { + try { + fullName = arg0.getDeclaration().getQualifiedName(); + packageName = arg0.getDeclaration().getPackage().getQualifiedName(); + + if (fullName.equals(String.class.getName())) { + fieldType = FieldType.STRING; + + } else if (fullName.equals(Boolean.class.getName())) { + fieldType = FieldType.BOOLEAN; + + } else if (fullName.equals(Locale.class.getName()) + || fullName.equals(Class.class.getName()) + || fullName.equals(Object.class.getName())) { + fieldType = FieldType.SIMPLE; + + } else if (isNumericSupported(fullName) + && Number.class.isAssignableFrom(Class.forName(fullName))) { + fieldType = FieldType.NUMERIC; + + } else if (arg0.getDeclaration().getAnnotation(Literal.class) != null) { + if (Comparable.class.isAssignableFrom(Class.forName(fullName))) { + fieldType = FieldType.COMPARABLE; + } else { + fieldType = FieldType.SIMPLE; + } + + } else if (isComparableSupported(fullName) + && Comparable.class.isAssignableFrom(Class + .forName(fullName))) { + fieldType = FieldType.COMPARABLE; + + } else if (asSimpleType(fullName)) { + fieldType = FieldType.SIMPLE; + + } + } catch (Exception e) { + throw new RuntimeException(e.getMessage(), e); + } + } + + private boolean isNumericSupported(String fullName) { + return isComparableSupported(fullName); + } + + private boolean isComparableSupported(String fullName) { + return fullName.startsWith("java.") || fullName.startsWith("javax.") + || fullName.startsWith("org.joda.time"); + } + + private boolean asSimpleType(String fullName) { + return false; + } + + public void visitEnumType(Class type) { + fieldType = FieldType.SIMPLE; + } + + @Override + public void visitEnumType(EnumType arg0) { + fieldType = FieldType.SIMPLE; + } + + public void visitInterfaceType(Class type, Type genericType) { + if (java.util.Map.class.isAssignableFrom(type)) { + handleMapInterface(type, genericType); + + } else if (java.util.List.class.isAssignableFrom(type)) { + handleListInterface(type, genericType); + + } else if (java.util.Collection.class.isAssignableFrom(type)) { + handleCollectionInterface(type, genericType); + } + + } + + @Override + public void visitInterfaceType(InterfaceType arg0) { + Iterator i = arg0.getActualTypeArguments().iterator(); + String typeName = arg0.getDeclaration().getQualifiedName(); + + if (typeName.equals(java.util.Map.class.getName())) { + handleMapInterface(i); + + } else if (typeName.equals(java.util.Collection.class.getName()) + || typeName.equals(java.util.Set.class.getName()) + || typeName.equals(java.util.SortedSet.class.getName())) { + handleCollectionInterface(i); + + } else if (typeName.equals(java.util.List.class.getName())) { + handleList(i); + } + } + + public void visitPrimitiveType(Class cl) { + visitPrimitiveWrapperType(ClassUtils.primitiveToWrapper(cl)); + } + + @Override + public void visitPrimitiveType(PrimitiveType arg0) { + Class cl = null; + switch (arg0.getKind()) { + case BOOLEAN: + cl = Boolean.class; + break; + case BYTE: + cl = Byte.class; + break; + case CHAR: + cl = Character.class; + break; + case DOUBLE: + cl = Double.class; + break; + case FLOAT: + cl = Float.class; + break; + case INT: + cl = Integer.class; + break; + case LONG: + cl = Long.class; + break; + case SHORT: + cl = Short.class; + break; + } + + visitPrimitiveWrapperType(cl); + } + + private void visitPrimitiveWrapperType(Class cl) { + if (cl.equals(Boolean.class)) { + fieldType = FieldType.BOOLEAN; + } else if (Number.class.isAssignableFrom(cl)) { + fieldType = FieldType.NUMERIC; + } else if (Comparable.class.isAssignableFrom(cl)) { + fieldType = FieldType.COMPARABLE; + } else { + fieldType = FieldType.SIMPLE; + } + fullName = cl.getName(); + simpleName = cl.getSimpleName(); + } + + @Override + public void visitTypeVariable(TypeVariable arg0) { + if (!arg0.getDeclaration().getBounds().isEmpty()) { + TypeHelper lb = new TypeHelper(arg0.getDeclaration().getBounds() + .iterator().next()); + fullName = lb.getFullName(); + packageName = lb.getPackageName(); + simpleName = lb.getSimpleName(); + fieldType = lb.getFieldType(); + } + } + + @Override + public void visitWildcardType(WildcardType arg0) { + if (!arg0.getUpperBounds().isEmpty()) { + TypeHelper lb = new TypeHelper(arg0.getUpperBounds().iterator() + .next()); + fullName = lb.getFullName(); + packageName = lb.getPackageName(); + simpleName = lb.getSimpleName(); + fieldType = lb.getFieldType(); + } + } + +} diff --git a/querydsl-apt-jdk5/src/main/java/com/mysema/query/apt/general/package-info.java b/querydsl-apt-jdk5/src/main/java/com/mysema/query/apt/general/package-info.java new file mode 100644 index 000000000..09e54186e --- /dev/null +++ b/querydsl-apt-jdk5/src/main/java/com/mysema/query/apt/general/package-info.java @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2009 Mysema Ltd. + * All rights reserved. + * + */ + +/** + * APT implementation classes + */ +package com.mysema.query.apt.general; + diff --git a/querydsl-apt-jdk5/src/main/java/com/mysema/query/apt/jdo/JDOProcessor.java b/querydsl-apt-jdk5/src/main/java/com/mysema/query/apt/jdo/JDOProcessor.java new file mode 100644 index 000000000..84103391c --- /dev/null +++ b/querydsl-apt-jdk5/src/main/java/com/mysema/query/apt/jdo/JDOProcessor.java @@ -0,0 +1,25 @@ +package com.mysema.query.apt.jdo; + +import static com.mysema.query.apt.Constants.*; + +import com.mysema.query.apt.general.DefaultEntityVisitor; +import com.mysema.query.apt.general.GeneralProcessor; +import com.sun.mirror.apt.AnnotationProcessorEnvironment; +import com.sun.mirror.declaration.MethodDeclaration; + +public class JDOProcessor extends GeneralProcessor { + + public JDOProcessor(AnnotationProcessorEnvironment env) { + super(env, JDO_ENTITY, JDO_ENTITY, QD_DTO); + } + + @Override + protected DefaultEntityVisitor createEntityVisitor() { + return new DefaultEntityVisitor() { + @Override + public void visitMethodDeclaration(MethodDeclaration d) { + // skip property handling + } + }; + } +} diff --git a/querydsl-apt-jdk5/src/main/java/com/mysema/query/apt/jpa/JPAProcessor.java b/querydsl-apt-jdk5/src/main/java/com/mysema/query/apt/jpa/JPAProcessor.java new file mode 100644 index 000000000..9c716c5a8 --- /dev/null +++ b/querydsl-apt-jdk5/src/main/java/com/mysema/query/apt/jpa/JPAProcessor.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2009 Mysema Ltd. + * All rights reserved. + * + */ +package com.mysema.query.apt.jpa; + +import static com.mysema.query.apt.Constants.*; + +import static com.sun.mirror.util.DeclarationVisitors.NO_OP; +import static com.sun.mirror.util.DeclarationVisitors.getDeclarationScanner; + +import java.util.Map; + +import com.mysema.query.apt.general.DefaultEntityVisitor; +import com.mysema.query.apt.general.GeneralProcessor; +import com.mysema.query.apt.model.Type; +import com.sun.mirror.apt.AnnotationProcessorEnvironment; +import com.sun.mirror.declaration.AnnotationTypeDeclaration; +import com.sun.mirror.declaration.Declaration; +import com.sun.mirror.declaration.MethodDeclaration; + +/** + * JpaProcessor provides JPA annotation handling support + * + * @author tiwe + * @version $Id$ + */ +public class JPAProcessor extends GeneralProcessor { + + public JPAProcessor(AnnotationProcessorEnvironment env) { + super(env, JPA_SUPERCLASS, JPA_ENTITY, QD_DTO); + } + + private void createEmbeddableClasses() { + DefaultEntityVisitor entityVisitor = new DefaultEntityVisitor(); + AnnotationTypeDeclaration a = (AnnotationTypeDeclaration) env + .getTypeDeclaration(JPA_EMBEDDABLE); + for (Declaration typeDecl : env.getDeclarationsAnnotatedWith(a)) { + typeDecl.accept(getDeclarationScanner(entityVisitor, NO_OP)); + } + + Map entityTypes = entityVisitor.types; + if (entityTypes.isEmpty()) { + env.getMessager().printNotice( + "No class generation for embeddable types"); + } else { + serializeAsOuterClasses(entityTypes.values(), EMBEDDABLE_OUTER_TMPL); + } + + } + + // TODO : add switch for field / getter handling + @Override + protected DefaultEntityVisitor createEntityVisitor() { + return new DefaultEntityVisitor() { + @Override + public void visitMethodDeclaration(MethodDeclaration d) { + // skip property handling + } + }; + } + + public void process() { + super.process(); + createEmbeddableClasses(); + } +} diff --git a/querydsl-apt-jdk5/src/main/java/com/mysema/query/apt/model/Constructor.java b/querydsl-apt-jdk5/src/main/java/com/mysema/query/apt/model/Constructor.java new file mode 100644 index 000000000..2e932c8f4 --- /dev/null +++ b/querydsl-apt-jdk5/src/main/java/com/mysema/query/apt/model/Constructor.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2009 Mysema Ltd. + * All rights reserved. + * + */ +package com.mysema.query.apt.model; + +import java.util.Collection; + +/** + * Constructor represents a constructor for a DTO query type. + * + * @author tiwe + * @version $Id$ + */ +public class Constructor { + private final Collection parameters; + + public Constructor(Collection params) { + parameters = params; + } + + public Collection getParameters() { + return parameters; + } + +} \ No newline at end of file diff --git a/querydsl-apt-jdk5/src/main/java/com/mysema/query/apt/model/Field.java b/querydsl-apt-jdk5/src/main/java/com/mysema/query/apt/model/Field.java new file mode 100644 index 000000000..c9791728a --- /dev/null +++ b/querydsl-apt-jdk5/src/main/java/com/mysema/query/apt/model/Field.java @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2009 Mysema Ltd. + * All rights reserved. + * + */ +package com.mysema.query.apt.model; + +/** + * Field represents a field / property in a query domain type. + * + * @author tiwe + * @version $Id$ + */ +public class Field implements Comparable { + + /** + * The Enum Type. + */ + + private final FieldType fieldType; + + private String name, realName, keyTypeName, typeName, typePackage, + simpleTypeName; + + /** + * Construct a new Field instance + * + * @param name + * normalized field name + * @param realName + * real fieldName + * @param keyTypeName + * key type name for Map types + * @param typePackage + * @param typeName + * full type name (with package) + * @param simpleTypeName + * simple type name (local) + * @param fieldType + */ + public Field(String name, String realName, String keyTypeName, + String typePackage, String typeName, String simpleTypeName, + FieldType fieldType) { + this.name = name; + this.realName = realName; + this.keyTypeName = keyTypeName; + this.typePackage = typePackage; + this.typeName = typeName; + this.simpleTypeName = simpleTypeName; + this.fieldType = fieldType; + } + + public int compareTo(Field o) { + return name.compareTo(o.name); + } + + public boolean equals(Object o) { + return o instanceof Field && name.equals(((Field) o).name); + } + + public FieldType getFieldType() { + return fieldType; + } + + /** + * Returns the type name of key element for Map fields + * + * @return + */ + public String getKeyTypeName() { + return keyTypeName; + } + + public String getName() { + return name; + } + + public String getRealName() { + return realName; + } + + /** + * Returns the simple name of the field type + * + * @return + */ + public String getSimpleTypeName() { + return simpleTypeName; + } + + /** + * Returns the full name of the field type + * + * @return + */ + public String getTypeName() { + return typeName; + } + + public String getTypePackage() { + return typePackage; + } + + public int hashCode() { + return name.hashCode(); + } + + public String toString() { + return typeName + " " + name; + } + +} \ No newline at end of file diff --git a/querydsl-apt-jdk5/src/main/java/com/mysema/query/apt/model/FieldType.java b/querydsl-apt-jdk5/src/main/java/com/mysema/query/apt/model/FieldType.java new file mode 100644 index 000000000..439d0fa89 --- /dev/null +++ b/querydsl-apt-jdk5/src/main/java/com/mysema/query/apt/model/FieldType.java @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2009 Mysema Ltd. + * All rights reserved. + * + */ +package com.mysema.query.apt.model; + +public enum FieldType { + BOOLEAN, COMPARABLE, ENTITY, ENTITYLIST, ENTITYCOLLECTION, ENTITYMAP, NUMERIC, SIMPLE, SIMPLELIST, SIMPLECOLLECTION, SIMPLEMAP, STRING +} \ No newline at end of file diff --git a/querydsl-apt-jdk5/src/main/java/com/mysema/query/apt/model/Parameter.java b/querydsl-apt-jdk5/src/main/java/com/mysema/query/apt/model/Parameter.java new file mode 100644 index 000000000..a3e3afb39 --- /dev/null +++ b/querydsl-apt-jdk5/src/main/java/com/mysema/query/apt/model/Parameter.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2009 Mysema Ltd. + * All rights reserved. + * + */ +package com.mysema.query.apt.model; + +/** + * Parameter represents a parameter in a Constructor + * + * @author tiwe + * @version $Id$ + */ +public class Parameter implements Comparable { + private final String name, typeName; + + public Parameter(String name, String typeName) { + this.name = name; + this.typeName = typeName; + } + + public int compareTo(Parameter o) { + return name.compareTo(o.name); + } + + public boolean equals(Object o) { + return o instanceof Parameter && name.equals(((Parameter) o).name); + } + + public String getName() { + return name; + } + + public String getTypeName() { + return typeName; + } + + public int hashCode() { + return name.hashCode(); + } +} \ No newline at end of file diff --git a/querydsl-apt-jdk5/src/main/java/com/mysema/query/apt/model/Type.java b/querydsl-apt-jdk5/src/main/java/com/mysema/query/apt/model/Type.java new file mode 100644 index 000000000..1239be366 --- /dev/null +++ b/querydsl-apt-jdk5/src/main/java/com/mysema/query/apt/model/Type.java @@ -0,0 +1,223 @@ +/* + * Copyright (c) 2009 Mysema Ltd. + * All rights reserved. + * + */ +package com.mysema.query.apt.model; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; +import java.util.TreeSet; + +import org.apache.commons.lang.StringUtils; + +/** + * Type represents a query domain type. + * + * @author tiwe + * @version $Id$ + */ +public class Type implements Comparable { + + private Set booleanFields = new TreeSet(); + + private Set comparableFields = new TreeSet(); + + private Set constructors = new HashSet(); + + private Set entityCollections = new TreeSet(); + + private Set entityFields = new TreeSet(); + + private Set entityLists = new TreeSet(); + + private Set entityMaps = new TreeSet(); + + private Set numericFields = new TreeSet(); + + private Set simpleCollections = new TreeSet(); + + private Set simpleFields = new TreeSet(); + + private Set simpleLists = new TreeSet(); + + private Set simpleMaps = new TreeSet(); + + private String simpleName, uncapSimpleName, name, packageName; + + private int escapeSuffix = 1; + + private Set stringFields = new TreeSet(); + + private String superType; + + public Type(String superType, String packageName, String name, + String simpleName) { + this.superType = superType; + this.packageName = packageName; + this.name = name; + this.simpleName = simpleName; + this.uncapSimpleName = StringUtils.uncapitalize(simpleName); + } + + public void addConstructor(Constructor co) { + constructors.add(co); + } + + public void addField(Field fieldDecl) { + validateField(fieldDecl); + switch (fieldDecl.getFieldType()) { + case BOOLEAN: + booleanFields.add(fieldDecl); + break; + case STRING: + stringFields.add(fieldDecl); + break; + case SIMPLE: + simpleFields.add(fieldDecl); + break; + case COMPARABLE: + comparableFields.add(fieldDecl); + break; + case NUMERIC: + numericFields.add(fieldDecl); + break; + case ENTITY: + entityFields.add(fieldDecl); + break; + case ENTITYCOLLECTION: + entityCollections.add(fieldDecl); + break; + case SIMPLECOLLECTION: + simpleCollections.add(fieldDecl); + break; + case ENTITYLIST: + entityLists.add(fieldDecl); + break; + case SIMPLELIST: + simpleLists.add(fieldDecl); + break; + case ENTITYMAP: + entityMaps.add(fieldDecl); + break; + case SIMPLEMAP: + simpleMaps.add(fieldDecl); + break; + } + } + + private Field validateField(Field field) { + if (field.getName().equals(this.uncapSimpleName)) { + uncapSimpleName = StringUtils.uncapitalize(simpleName) + + (escapeSuffix++); + } + return field; + } + + public int compareTo(Type o) { + return simpleName.compareTo(o.simpleName); + } + + public boolean equals(Object o) { + return o instanceof Type && simpleName.equals(((Type) o).simpleName); + } + + public Collection getBooleanFields() { + return booleanFields; + } + + public Collection getComparableFields() { + return comparableFields; + } + + public Collection getConstructors() { + return constructors; + } + + public Collection getEntityCollections() { + return entityCollections; + } + + public Collection getEntityFields() { + return entityFields; + } + + public Collection getEntityLists() { + return entityLists; + } + + public Collection getEntityMaps() { + return entityMaps; + } + + public String getName() { + return name; + } + + public Collection getNumericFields() { + return numericFields; + } + + public String getPackageName() { + return packageName; + } + + public Collection getSimpleCollections() { + return simpleCollections; + } + + public Collection getSimpleFields() { + return simpleFields; + } + + public Collection getSimpleLists() { + return simpleLists; + } + + public Collection getSimpleMaps() { + return simpleMaps; + } + + public String getSimpleName() { + return simpleName; + } + + public String getUncapSimpleName() { + return uncapSimpleName; + } + + public Collection getStringFields() { + return stringFields; + } + + public String getSupertypeName() { + return superType; + } + + public int hashCode() { + return name.hashCode(); + } + + public void include(Type decl) { + addAll(booleanFields, decl.booleanFields); + addAll(entityCollections, decl.entityCollections); + addAll(entityFields, decl.entityFields); + addAll(entityLists, decl.entityLists); + addAll(entityMaps, decl.entityMaps); + addAll(comparableFields, decl.comparableFields); + addAll(numericFields, decl.numericFields); + addAll(simpleCollections, decl.simpleCollections); + addAll(simpleFields, decl.simpleFields); + addAll(simpleLists, decl.simpleLists); + addAll(simpleMaps, decl.simpleMaps); + addAll(stringFields, decl.stringFields); + } + + private void addAll(Set target, Set source) { + for (Field field : source) { + target.add(validateField(field)); + } + } + +} \ No newline at end of file diff --git a/querydsl-apt-jdk5/src/main/java/com/mysema/query/apt/package-info.java b/querydsl-apt-jdk5/src/main/java/com/mysema/query/apt/package-info.java new file mode 100644 index 000000000..c1a48ac2e --- /dev/null +++ b/querydsl-apt-jdk5/src/main/java/com/mysema/query/apt/package-info.java @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2008 Mysema Ltd. + * All rights reserved. + * + */ + +/** + * APTFactory and related classes + */ +package com.mysema.query.apt; + diff --git a/querydsl-apt-jdk5/src/main/resources/META-INF/services/com.sun.mirror.apt.AnnotationProcessorFactory b/querydsl-apt-jdk5/src/main/resources/META-INF/services/com.sun.mirror.apt.AnnotationProcessorFactory new file mode 100644 index 000000000..d39d5ee7f --- /dev/null +++ b/querydsl-apt-jdk5/src/main/resources/META-INF/services/com.sun.mirror.apt.AnnotationProcessorFactory @@ -0,0 +1 @@ +com.mysema.query.apt.APTFactory \ No newline at end of file diff --git a/querydsl-apt-jdk5/src/main/resources/domain-as-outer-classes.ftl b/querydsl-apt-jdk5/src/main/resources/domain-as-outer-classes.ftl new file mode 100644 index 000000000..a1c65f962 --- /dev/null +++ b/querydsl-apt-jdk5/src/main/resources/domain-as-outer-classes.ftl @@ -0,0 +1,12 @@ +<#import "/macros.ftl" as cl> +package ${package}; + +import com.mysema.query.types.path.*; + +/** + * ${pre}${classSimpleName} is a Querydsl query type for ${classSimpleName} + * + */ +public class ${pre}${classSimpleName} extends PEntity<${type.name}>{ +<@cl.classContent decl=type embeddable=false/> +} diff --git a/querydsl-apt-jdk5/src/main/resources/dto-as-outer-classes.ftl b/querydsl-apt-jdk5/src/main/resources/dto-as-outer-classes.ftl new file mode 100644 index 000000000..d0f869455 --- /dev/null +++ b/querydsl-apt-jdk5/src/main/resources/dto-as-outer-classes.ftl @@ -0,0 +1,16 @@ +<#import "/macros.ftl" as cl> +package ${package}; + +import com.mysema.query.types.expr.*; + +/** + * ${pre}${classSimpleName} is a Querydsl DTO type + * + */ +public class ${pre}${classSimpleName} extends EConstructor<${type.name}>{ + <#list type.constructors as co> + public ${pre}${type.simpleName}(<#list co.parameters as pa>Expr<${pa.typeName}> ${pa.name}<#if pa_has_next>,){ + super(${type.name}.class<#list co.parameters as pa>,${pa.name}); + } + +} diff --git a/querydsl-apt-jdk5/src/main/resources/embeddable-as-outer-classes.ftl b/querydsl-apt-jdk5/src/main/resources/embeddable-as-outer-classes.ftl new file mode 100644 index 000000000..2cf10be28 --- /dev/null +++ b/querydsl-apt-jdk5/src/main/resources/embeddable-as-outer-classes.ftl @@ -0,0 +1,12 @@ +<#import "/macros.ftl" as cl> +package ${package}; + +import com.mysema.query.types.path.*; + +/** + * ${pre}${classSimpleName} is a Querydsl embeddable type + * + */ +public class ${pre}${classSimpleName} extends PEntity<${type.name}>{ +<@cl.classContent decl=type embeddable=true/> +} diff --git a/querydsl-apt-jdk5/src/main/resources/macros.ftl b/querydsl-apt-jdk5/src/main/resources/macros.ftl new file mode 100644 index 000000000..ca21ee73c --- /dev/null +++ b/querydsl-apt-jdk5/src/main/resources/macros.ftl @@ -0,0 +1,141 @@ +<#assign reserved = ["isnull", "isnotnull", "getType", "getMetadata", "toString", "hashCode", "getClass", "notify", "notifyAll", "wait"]> + +<#macro classContent decl embeddable> + <#if !embeddable> + public static final ${pre}${decl.simpleName} ${decl.uncapSimpleName} = new ${pre}${decl.simpleName}("${decl.uncapSimpleName}"); + + <#list decl.stringFields as field> + <@stringField field=field/> + + <#list decl.booleanFields as field> + <@booleanField field=field/> + + <#list decl.simpleFields as field> + <@simpleField field=field/> + + <#list decl.comparableFields as field> + <@comparableField field=field/> + + <#list decl.numericFields as field> + <@numericField field=field/> + + <#list decl.simpleMaps as field> + <@simpleMap field=field/> + + <#list decl.simpleCollections as field> + <@simpleCollection field=field/> + + <#list decl.simpleLists as field> + <@simpleList field=field/> + + <#list decl.entityMaps as field> + <@entityMap field=field/> + + <#list decl.entityCollections as field> + <@entityCollection field=field/> + + <#list decl.entityLists as field> + <@entityList field=field/> + + <#list decl.entityFields as field> + <@entityField field=field/> + + + <#-- constructors --> + <#if !embeddable> + public ${pre}${decl.simpleName}(java.lang.String path) { + this(${decl.name}.class, path); + } + public ${pre}${decl.simpleName}(Class cl, java.lang.String path) { + super(cl, "${decl.simpleName}", path); + <#list decl.entityFields as field> + <#if !reserved?seq_contains(field.name)> + _${field.name}(); + + + } + + public ${pre}${decl.simpleName}(PathMetadata metadata) { + super(${decl.name}.class, "${decl.simpleName}", metadata); + } + + +<#macro booleanField field> + public final PBoolean ${field.name} = _boolean("${field.realName}"); + + +<#macro comparableField field> + public final PComparable<${field.typeName}> ${field.name} = _comparable("${field.realName}",${field.typeName}.class); + + +<#macro entityCollection field> + public final PEntityCollection<${field.typeName}> ${field.name} = _entitycol("${field.realName}",${field.typeName}.class, "${field.simpleTypeName}"); + + +<#macro entityField field> + public ${field.typePackage}.${pre}${field.simpleTypeName} ${field.name}; + <#if !reserved?seq_contains(field.name)> + public ${field.typePackage}.${pre}${field.simpleTypeName} _${field.name}() { + if (${field.name} == null) ${field.name} = new ${field.typePackage}.${pre}${field.simpleTypeName}(PathMetadata.forProperty(this,"${field.realName}")); + return ${field.name}; + } + + + +<#macro entityList field> + public final PEntityList<${field.typeName}> ${field.name} = _entitylist("${field.realName}",${field.typeName}.class,"${field.simpleTypeName}"); + public ${field.typePackage}.${pre}${field.simpleTypeName} ${field.name}(int index) { + return new ${field.typePackage}.${pre}${field.simpleTypeName}(PathMetadata.forListAccess(${field.name},index)); + } + public ${field.typePackage}.${pre}${field.simpleTypeName} ${field.name}(com.mysema.query.types.expr.Expr index) { + return new ${field.typePackage}.${pre}${field.simpleTypeName}(PathMetadata.forListAccess(${field.name},index)); + } + + +<#macro entityMap field> + public final PEntityMap<${field.keyTypeName},${field.typeName}> ${field.name} = _entitymap("${field.realName}",${field.keyTypeName}.class,${field.typeName}.class,"${field.simpleTypeName}"); + public ${field.typePackage}.${pre}${field.simpleTypeName} ${field.name}(${field.keyTypeName} key) { + return new ${field.typePackage}.${pre}${field.simpleTypeName}(PathMetadata.forMapAccess(${field.name},key)); + } + public ${field.typePackage}.${pre}${field.simpleTypeName} ${field.name}(com.mysema.query.types.expr.Expr<${field.keyTypeName}> key) { + return new ${field.typePackage}.${pre}${field.simpleTypeName}(PathMetadata.forMapAccess(${field.name},key)); + } + + +<#macro numericField field> + public final PNumber<${field.typeName}> ${field.name} = _number("${field.realName}",${field.typeName}.class); + + +<#macro simpleField field> + public final PSimple<${field.typeName}> ${field.name} = _simple("${field.realName}",${field.typeName}.class); + + +<#macro simpleMap field> + public final PComponentMap<${field.keyTypeName},${field.typeName}> ${field.name} = _simplemap("${field.realName}",${field.keyTypeName}.class,${field.typeName}.class); + public PSimple<${field.typeName}> ${field.name}(${field.keyTypeName} key) { + return new PSimple<${field.typeName}>(${field.typeName}.class,PathMetadata.forMapAccess(${field.name},key)); + } + public PSimple<${field.typeName}> ${field.name}(com.mysema.query.types.expr.Expr<${field.keyTypeName}> key) { + return new PSimple<${field.typeName}>(${field.typeName}.class,PathMetadata.forMapAccess(${field.name},key)); + } + + +<#macro simpleCollection field> + public final PComponentCollection<${field.typeName}> ${field.name} = _simplecol("${field.realName}",${field.typeName}.class); + + +<#macro simpleList field> + public final PComponentList<${field.typeName}> ${field.name} = _simplelist("${field.realName}",${field.typeName}.class); + public PSimple<${field.typeName}> ${field.name}(int index) { + return new PSimple<${field.typeName}>(${field.typeName}.class,PathMetadata.forListAccess(${field.name},index)); + } + public PSimple<${field.typeName}> ${field.name}(com.mysema.query.types.expr.Expr index) { + return new PSimple<${field.typeName}>(${field.typeName}.class,PathMetadata.forListAccess(${field.name},index)); + } + + +<#macro stringField field> + public final PString ${field.name} = _string("${field.realName}"); + + + diff --git a/querydsl-apt-jdk5/src/site/site.xml b/querydsl-apt-jdk5/src/site/site.xml new file mode 100644 index 000000000..eb63342ce --- /dev/null +++ b/querydsl-apt-jdk5/src/site/site.xml @@ -0,0 +1,16 @@ + + + /images/logos/header_mysema_logo.png + http://source.mysema.com + + + + ${project.name} + /index.html + + + + + + + \ No newline at end of file diff --git a/querydsl-apt-jdk5/src/test/java/com/mysema/query/apt/general/GeneralProcessorTest.java b/querydsl-apt-jdk5/src/test/java/com/mysema/query/apt/general/GeneralProcessorTest.java new file mode 100644 index 000000000..7a1a180f6 --- /dev/null +++ b/querydsl-apt-jdk5/src/test/java/com/mysema/query/apt/general/GeneralProcessorTest.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2009 Mysema Ltd. + * All rights reserved. + * + */ +package com.mysema.query.apt.general; + +import java.io.StringWriter; +import java.io.Writer; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import org.junit.Test; + +import com.mysema.query.apt.model.Constructor; +import com.mysema.query.apt.model.Field; +import com.mysema.query.apt.model.FieldType; +import com.mysema.query.apt.model.Parameter; +import com.mysema.query.apt.model.Type; + +/** + * HibernateProcessorTest provides. + * + * @author tiwe + * @version $Id$ + */ +public class GeneralProcessorTest { + + private Type type; + + private Writer writer = new StringWriter(); + + private Map model = new HashMap(); + + public GeneralProcessorTest() { + type = new Type("com.mysema.query.DomainSuperClass", + "com.mysema.query", "com.mysema.query.DomainClass", + "DomainClass"); + + Field field = new Field("field", "field", null, "java.lang", + "java.lang.String", "String", FieldType.STRING); + type.addField(field); + Parameter param = new Parameter("name", "java.lang.String"); + type.addConstructor(new Constructor(Collections.singleton(param))); + } + + @Test + public void testDomainTypesAsOuterClasses() throws Exception { + model.put("type", type); + model.put("pre", ""); + model.put("include", ""); + model.put("package", "com.mysema.query"); + model.put("classSimpleName", "Test"); + + // as outer classes + GeneralProcessor.DOMAIN_OUTER_TMPL.serialize(model, writer); + } + +} diff --git a/querydsl-apt-jdk5/src/test/java/com/mysema/query/apt/general/TypeHelperTest.java b/querydsl-apt-jdk5/src/test/java/com/mysema/query/apt/general/TypeHelperTest.java new file mode 100644 index 000000000..d78e44912 --- /dev/null +++ b/querydsl-apt-jdk5/src/test/java/com/mysema/query/apt/general/TypeHelperTest.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2009 Mysema Ltd. + * All rights reserved. + * + */ +package com.mysema.query.apt.general; + +import static org.junit.Assert.assertEquals; + +import java.util.Collection; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; + +import org.junit.Test; + +import com.mysema.query.apt.model.Field; +import com.mysema.query.apt.model.Type; + +/** + * TypeHelperTest provides + * + * @author tiwe + * @version $Id$ + */ +public class TypeHelperTest { + + @Test + public void test() { + Type type = TypeFactory.createType(TestType.class); + assertEquals(1, type.getEntityMaps().size()); + assertEquals(1, type.getSimpleMaps().size()); + assertEquals(2, type.getEntityCollections().size()); + assertEquals(2, type.getSimpleCollections().size()); + assertEquals(1, type.getEntityLists().size()); + assertEquals(1, type.getSimpleLists().size()); + assertEquals(1, type.getEntityFields().size()); + assertEquals(1, type.getStringFields().size()); + assertEquals(2, type.getNumericFields().size()); + assertEquals(3, type.getSimpleFields().size()); + } + + public static class TestType { + // entity map + public Map map1; + // simple map + public Map map2; + // entity col + public Collection col1; + public Set set1; + // simple col + public Collection col2; + public Set set2; + // entity list + public List list1; + // simple list + public List list2; + // entity + public TestType ref; + // string + public String str; + // numeric + public int intField; + public Integer intField2; + // simple + public Class cl; + public Object o; + public Locale l; + } + +}