diff --git a/querydsl-apt/src/main/java/com/mysema/query/apt/FreeMarkerSerializer.java b/querydsl-apt/src/main/java/com/mysema/query/apt/FreeMarkerSerializer.java deleted file mode 100644 index 08f8b9c9a..000000000 --- a/querydsl-apt/src/main/java/com/mysema/query/apt/FreeMarkerSerializer.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * 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.Template; -import freemarker.template.TemplateException; - -/** - * FreeMarkerSerializer provides. - * - * @author tiwe - * @version $Id$ - */ -public final class FreeMarkerSerializer { - - private final Configuration cfg; - - private final String templateLocation; - - public FreeMarkerSerializer(String template){ - if (template == null) throw new IllegalArgumentException("template was null"); - cfg = new Configuration(); - cfg.setClassForTemplateLoading(this.getClass(), "/"); - cfg.setObjectWrapper(new DefaultObjectWrapper()); - templateLocation = template; - } - - public void serialize(Map model, Writer writer) throws IOException, TemplateException{ - Template template = cfg.getTemplate(templateLocation); - template.process(model, writer); - writer.flush(); - } - -} diff --git a/querydsl-apt/src/main/java/com/mysema/query/apt/Serializer.java b/querydsl-apt/src/main/java/com/mysema/query/apt/Serializer.java new file mode 100644 index 000000000..fcd17ff39 --- /dev/null +++ b/querydsl-apt/src/main/java/com/mysema/query/apt/Serializer.java @@ -0,0 +1,50 @@ +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; + +/** + * Serializer provides + * + * @author tiwe + * @version $Id$ + */ +public interface Serializer { + + /** + * + * @param model + * @param writer + * @throws Exception + */ + public void serialize(Map model, Writer writer) throws Exception; + + public final class FreeMarker implements Serializer{ + + private static final Configuration cfg; + + static { + cfg = new Configuration(); + cfg.setClassForTemplateLoading(Serializer.class, "/"); + cfg.setObjectWrapper(new DefaultObjectWrapper()); + } + + private final String templateLocation; + + public FreeMarker(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/src/main/java/com/mysema/query/apt/hibernate/HibernateProcessor.java b/querydsl-apt/src/main/java/com/mysema/query/apt/hibernate/HibernateProcessor.java index 787d018ed..9ced826f6 100644 --- a/querydsl-apt/src/main/java/com/mysema/query/apt/hibernate/HibernateProcessor.java +++ b/querydsl-apt/src/main/java/com/mysema/query/apt/hibernate/HibernateProcessor.java @@ -8,18 +8,15 @@ package com.mysema.query.apt.hibernate; import static com.sun.mirror.util.DeclarationVisitors.NO_OP; import static com.sun.mirror.util.DeclarationVisitors.getDeclarationScanner; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStreamWriter; -import java.io.Writer; +import java.io.*; +import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.TreeSet; import org.apache.commons.io.FileUtils; -import com.mysema.query.apt.FreeMarkerSerializer; +import com.mysema.query.apt.Serializer; import com.mysema.query.apt.Type; import com.sun.mirror.apt.AnnotationProcessor; import com.sun.mirror.apt.AnnotationProcessorEnvironment; @@ -33,20 +30,26 @@ import com.sun.mirror.declaration.Declaration; * @version $Id$ */ public class HibernateProcessor implements AnnotationProcessor { + + static final Serializer + DOMAIN_INNER_TMPL = new Serializer.FreeMarker("/domain-as-inner-classes.ftl"), + DOMAIN_OUTER_TMPL = new Serializer.FreeMarker("/domain-as-outer-classes.ftl"), + DTO_INNER_TMPL = new Serializer.FreeMarker("/dto-as-inner-classes.ftl"), + DTO_OUTER_TMPL = new Serializer.FreeMarker("/dto-as-outer-classes.ftl"); private final String destClass, destPackage, dtoClass, dtoPackage; - private final String include, namePrefix, targetFolder; - private final AnnotationProcessorEnvironment env; + private final String include, namePrefix, targetFolder; + public HibernateProcessor(AnnotationProcessorEnvironment env) throws IOException { this.env = env; this.targetFolder = env.getOptions().get("-s"); - this.destClass = getString(env.getOptions(), "-AdestClass=", ""); - this.destPackage = getString(env.getOptions(), "-AdestPackage=", ""); - this.dtoClass = getString(env.getOptions(), "-AdtoClass=", ""); - this.dtoPackage = getString(env.getOptions(), "-AdtoPackage=", ""); + this.destClass = getString(env.getOptions(), "-AdestClass=", null); + this.destPackage = getString(env.getOptions(), "-AdestPackage=", null); + this.dtoClass = getString(env.getOptions(), "-AdtoClass=", null); + this.dtoPackage = getString(env.getOptions(), "-AdtoPackage=", null); this.include = getFileContent(env.getOptions(), "-Ainclude=", ""); this.namePrefix = getString(env.getOptions(), "-AnamePrefix=", ""); } @@ -84,8 +87,7 @@ public class HibernateProcessor implements AnnotationProcessor { // domain types visitor1 = new EntityVisitor(); - a = (AnnotationTypeDeclaration) env - .getTypeDeclaration("javax.persistence.Entity"); + a = (AnnotationTypeDeclaration) env.getTypeDeclaration("javax.persistence.Entity"); for (Declaration typeDecl : env.getDeclarationsAnnotatedWith(a)) { typeDecl.accept(getDeclarationScanner(visitor1, NO_OP)); } @@ -95,21 +97,13 @@ public class HibernateProcessor implements AnnotationProcessor { addSupertypeFields(typeDecl, entityTypes, mappedSupertypes); } - // populate model - Map model = new HashMap(); - model.put("domainTypes", new TreeSet(entityTypes.values())); - model.put("pre", namePrefix); - model.put("include", include); - model.put("package", destClass.substring(0, destClass.lastIndexOf('.'))); - model.put("classSimpleName", destClass.substring(destClass.lastIndexOf('.') + 1)); - - // serialize it - String path = destClass.replace('.', '/') + ".java"; - File file = new File(targetFolder, path); - if (!file.getParentFile().mkdirs()){ - System.err.println("Folder " + file.getParent() + " could not be created"); + if (destClass != null){ + serializeAsInnerClasses(entityTypes.values()); + }else if (destPackage != null){ + serializeAsOuterClasses(entityTypes.values()); + }else{ + System.err.print("No class generation for domain types"); } - serialize(file, "/querydsl-hibernate-domain.ftl", model); } @@ -121,22 +115,15 @@ public class HibernateProcessor implements AnnotationProcessor { typeDecl.accept(getDeclarationScanner(visitor2, NO_OP)); } - // populate model - Map model = new HashMap(); - model.put("dtoTypes", visitor2.types); - model.put("pre", namePrefix); - model.put("package", dtoClass.substring(0, dtoClass.lastIndexOf('.'))); - model.put("classSimpleName", dtoClass.substring(dtoClass.lastIndexOf('.') + 1)); - - // serialize it - String path = dtoClass.replace('.', '/') + ".java"; - File file = new File(targetFolder, path); - if (!file.getParentFile().mkdirs()){ - System.err.println("Folder " + file.getParent() + " could not be created"); + if (dtoClass != null){ + serializeDTOsAsInnerClasses(visitor2.types); + }else if (dtoPackage != null){ + serializeDTOsAsOuterClasses(visitor2.types); + }else{ + System.err.print("No class generation for DTO types"); } - serialize(file, "/querydsl-hibernate-dto.ftl", model); } - + private String getFileContent(Map options, String prefix, String defaultValue) throws IOException { for (Map.Entry entry : options.entrySet()) { @@ -147,7 +134,8 @@ public class HibernateProcessor implements AnnotationProcessor { } return defaultValue; } - + + private String getString(Map options, String prefix, String defaultValue) { for (Map.Entry entry : options.entrySet()) { @@ -163,14 +151,108 @@ public class HibernateProcessor implements AnnotationProcessor { if (!"".equals(dtoClass)) createDTOClasses(); } - private void serialize(File file, String template, Map model){ + private void serializeAsInnerClasses(Collection entityTypes) { + // populate model + Map model = new HashMap(); + model.put("domainTypes", new TreeSet(entityTypes)); + model.put("pre", namePrefix); + model.put("include", include); + model.put("package", destClass.substring(0, destClass.lastIndexOf('.'))); + model.put("classSimpleName", destClass.substring(destClass.lastIndexOf('.') + 1)); + + // serialize it + String path = destClass.replace('.', '/') + ".java"; + File file = new File(targetFolder, path); + if (!file.getParentFile().exists() && !file.getParentFile().mkdirs()){ + System.err.println("Folder " + file.getParent() + " could not be created"); + } try { - Writer out = new OutputStreamWriter(new FileOutputStream(file)); - new FreeMarkerSerializer(template).serialize(model, out); - } catch (Exception e) { + DOMAIN_INNER_TMPL.serialize(model, writerFor(file)); + } catch (Exception e) { + throw new RuntimeException("Caught exception",e); + } + } + + + private void serializeAsOuterClasses(Collection entityTypes) { + // populate model + Map model = new HashMap(); + model.put("pre", namePrefix); + model.put("include", include); + model.put("package", destPackage); + + for (Type type : entityTypes){ + model.put("type", type); + model.put("classSimpleName", type.getSimpleName()); + + // serialize it + String path = destPackage.replace('.', '/') + "/" + namePrefix + type.getSimpleName() + ".java"; + File file = new File(targetFolder, path); + if (!file.getParentFile().exists() && !file.getParentFile().mkdirs()){ + System.err.println("Folder " + file.getParent() + " could not be created"); + } + try { + DOMAIN_OUTER_TMPL.serialize(model, writerFor(file)); + } catch (Exception e) { + throw new RuntimeException("Caught exception",e); + } + } + } + + private void serializeDTOsAsInnerClasses(Collection types) { + // populate model + Map model = new HashMap(); + model.put("dtoTypes", types); + model.put("pre", namePrefix); + model.put("package", dtoClass.substring(0, dtoClass.lastIndexOf('.'))); + model.put("classSimpleName", dtoClass.substring(dtoClass.lastIndexOf('.') + 1)); + + // serialize it + String path = dtoClass.replace('.', '/') + ".java"; + File file = new File(targetFolder, path); + if (!file.getParentFile().mkdirs()){ + System.err.println("Folder " + file.getParent() + " could not be created"); + } + try { + DTO_INNER_TMPL.serialize(model, writerFor(file)); + } catch (Exception e) { + throw new RuntimeException("Caught exception",e); + } + } + + private void serializeDTOsAsOuterClasses(Collection types){ + // populate model + Map model = new HashMap(); + model.put("pre", namePrefix); + model.put("include", include); + model.put("package", dtoPackage); + + for (Type type : types){ + model.put("type", type); + model.put("classSimpleName", type.getSimpleName()); + + // serialize it + String path = dtoPackage.replace('.', '/') + "/" + namePrefix + type.getSimpleName() + ".java"; + File file = new File(targetFolder, path); + if (!file.getParentFile().exists() && !file.getParentFile().mkdirs()){ + System.err.println("Folder " + file.getParent() + " could not be created"); + } + try { + DTO_OUTER_TMPL.serialize(model, writerFor(file)); + } catch (Exception e) { + throw new RuntimeException("Caught exception",e); + } + } + + } + + private Writer writerFor(File file){ + try { + return new OutputStreamWriter(new FileOutputStream(file)); + } catch (FileNotFoundException e) { String error = "Caught " + e.getClass().getName(); throw new RuntimeException(error, e); } } - + } \ No newline at end of file diff --git a/querydsl-apt/src/main/resources/domain-as-inner-classes.ftl b/querydsl-apt/src/main/resources/domain-as-inner-classes.ftl new file mode 100644 index 000000000..85b880520 --- /dev/null +++ b/querydsl-apt/src/main/resources/domain-as-inner-classes.ftl @@ -0,0 +1,20 @@ +<#import "/macros.ftl" as cl> +package ${package}; + +import com.mysema.query.grammar.types.*; +import static com.mysema.query.grammar.types.PathMetadata.*; + +/** + * ${classSimpleName} provides types for use in Query DSL constructs + * + */ +public class ${classSimpleName} { +${include} +<#list domainTypes as type> + public static final class ${pre}${type.simpleName} extends Path.Entity<${type.name}>{ + <@cl.classContent decl=type/> + } + + + +} diff --git a/querydsl-apt/src/main/resources/domain-as-outer-classes.ftl b/querydsl-apt/src/main/resources/domain-as-outer-classes.ftl new file mode 100644 index 000000000..9dca5e0dc --- /dev/null +++ b/querydsl-apt/src/main/resources/domain-as-outer-classes.ftl @@ -0,0 +1,13 @@ +<#import "/macros.ftl" as cl> +package ${package}; + +import com.mysema.query.grammar.types.*; +import static com.mysema.query.grammar.types.PathMetadata.*; + +/** + * ${classSimpleName} provides types for use in Query DSL constructs + * + */ +public class ${pre}${classSimpleName} extends Path.Entity<${type.name}>{ +<@cl.classContent decl=type/> +} diff --git a/querydsl-apt/src/main/resources/querydsl-hibernate-dto.ftl b/querydsl-apt/src/main/resources/dto-as-inner-classes.ftl similarity index 100% rename from querydsl-apt/src/main/resources/querydsl-hibernate-dto.ftl rename to querydsl-apt/src/main/resources/dto-as-inner-classes.ftl diff --git a/querydsl-apt/src/main/resources/dto-as-outer-classes.ftl b/querydsl-apt/src/main/resources/dto-as-outer-classes.ftl new file mode 100644 index 000000000..e08a6d282 --- /dev/null +++ b/querydsl-apt/src/main/resources/dto-as-outer-classes.ftl @@ -0,0 +1,17 @@ +<#import "/macros.ftl" as cl> +package ${package}; + +import static com.mysema.query.grammar.types.HqlTypes.*; +import com.mysema.query.grammar.types.*; + +/** + * ${classSimpleName} provides types for use in Query DSL constructs + * + */ +public class ${pre}${classSimpleName} extends Constructor<${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/src/main/resources/querydsl-hibernate-domain.ftl b/querydsl-apt/src/main/resources/macros.ftl similarity index 82% rename from querydsl-apt/src/main/resources/querydsl-hibernate-domain.ftl rename to querydsl-apt/src/main/resources/macros.ftl index c5f3ed8f4..b85cbf480 100644 --- a/querydsl-apt/src/main/resources/querydsl-hibernate-domain.ftl +++ b/querydsl-apt/src/main/resources/macros.ftl @@ -1,26 +1,13 @@ -<#assign reserved = ["isnull", "isnotnull", "getType", "getMetadata", "toString", "hashCode", "getClass", "notify", "notifyAll", "wait"]> -package ${package}; - -import com.mysema.query.grammar.types.*; -import static com.mysema.query.grammar.types.PathMetadata.*; - -/** - * ${classSimpleName} provides types for use in Query DSL constructs - * - */ -public class ${classSimpleName} { -${include} -<#list domainTypes as decl> - public static final class ${pre}${decl.simpleName} extends Path.Entity<${decl.name}>{ - <#list decl.stringFields as field> +<#macro classContent decl> + <#assign reserved = ["isnull", "isnotnull", "getType", "getMetadata", "toString", "hashCode", "getClass", "notify", "notifyAll", "wait"]> + <#list decl.stringFields as field> public final Path.String ${field.name} = _string("${field.name}"); <#list decl.booleanFields as field> public final Path.Boolean ${field.name} = _boolean("${field.name}"); -<#-- - simple fields ---> + + <#-- simple fields --> <#list decl.simpleFields as field> public final Path.Comparable<${field.typeName}> ${field.name} = _comparable("${field.name}",${field.typeName}.class); @@ -45,9 +32,8 @@ ${include} return new Path.Simple<${field.typeName}>(${field.typeName}.class,forListAccess(${field.name},index)); } -<#-- - entity fields ---> + + <#-- entity fields --> <#list decl.entityMaps as field> public final Path.EntityMap<${field.keyTypeName},${field.typeName}> ${field.name} = _entitymap("${field.name}",${field.keyTypeName}.class,${field.typeName}.class); public ${pre}${field.simpleTypeName} ${field.name}(${field.keyTypeName} key) { @@ -78,9 +64,8 @@ ${include} } -<#-- - constructors ---> + + <#-- constructors --> public ${pre}${decl.simpleName}(java.lang.String path) { super(${decl.name}.class, path); <#list decl.entityFields as field> @@ -92,8 +77,4 @@ ${include} public ${pre}${decl.simpleName}(PathMetadata metadata) { super(${decl.name}.class, metadata); } - } - - - -} + \ No newline at end of file diff --git a/querydsl-apt/src/test/java/com/mysema/query/apt/hibernate/HibernateProcessorTest.java b/querydsl-apt/src/test/java/com/mysema/query/apt/hibernate/HibernateProcessorTest.java index 14c672e1d..1f4c7d45b 100644 --- a/querydsl-apt/src/test/java/com/mysema/query/apt/hibernate/HibernateProcessorTest.java +++ b/querydsl-apt/src/test/java/com/mysema/query/apt/hibernate/HibernateProcessorTest.java @@ -5,17 +5,18 @@ */ package com.mysema.query.apt.hibernate; -import java.io.IOException; 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.*; - -import freemarker.template.TemplateException; +import com.mysema.query.apt.Constructor; +import com.mysema.query.apt.Field; +import com.mysema.query.apt.Parameter; +import com.mysema.query.apt.Type; /** * HibernateProcessorTest provides. @@ -24,36 +25,54 @@ import freemarker.template.TemplateException; * @version $Id$ */ public class HibernateProcessorTest { + + private Type type; + + private Writer writer = new StringWriter(); + + private Map model = new HashMap(); + public HibernateProcessorTest(){ + type = new Type("com.mysema.query.DomainSuperClass","com.mysema.query.DomainClass","DomainClass"); + Field field = new Field("field",null,"java.lang.String","java.lang.String",Field.Type.STRING); + type.addField(field); + Parameter param = new Parameter("name","java.lang.String"); + type.addConstructor( new Constructor(Collections.singleton(param))); + } + @Test - public void testDomainTypes() throws IOException, TemplateException{ - Map model = new HashMap(); - model.put("domainTypes", Collections.singleton(createTypeDecl())); + public void testDomainTypesAsInnerClass() throws Exception{ + model.put("domainTypes", Collections.singleton(type)); model.put("pre", ""); model.put("include", ""); model.put("package", "com.mysema.query"); model.put("classSimpleName", "Test"); - StringWriter writer = new StringWriter(); - new FreeMarkerSerializer("/querydsl-hibernate-domain.ftl").serialize(model, writer); + + // as inner classes + HibernateProcessor.DOMAIN_INNER_TMPL.serialize(model, writer); + } + + @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 + HibernateProcessor.DOMAIN_OUTER_TMPL.serialize(model, writer); } @Test - public void testDTOTypes() throws IOException, TemplateException{ - Map model = new HashMap(); - model.put("dtoTypes", Collections.singleton(createTypeDecl())); + public void testDTOTypes() throws Exception{ + model.put("dtoTypes", Collections.singleton(type)); model.put("pre", ""); model.put("package", "com.mysema.query"); model.put("classSimpleName", "Test"); - StringWriter writer = new StringWriter(); - new FreeMarkerSerializer("/querydsl-hibernate-dto.ftl").serialize(model, writer); - } - - private Type createTypeDecl() { - Type typeDecl = new Type("com.mysema.query.DomainSuperClass","com.mysema.query.DomainClass","DomainClass"); - Field field = new Field("field",null,"java.lang.String","java.lang.String",Field.Type.STRING); - typeDecl.addField(field); - Parameter param = new Parameter("name","java.lang.String"); - typeDecl.addConstructor( new Constructor(Collections.singleton(param))); - return typeDecl; + + // as inner classes + HibernateProcessor.DTO_INNER_TMPL.serialize(model, writer); } + }