diff --git a/examples/plugins/csv/pom.xml b/examples/plugins/csv/pom.xml index e205e2a5..a511df0f 100644 --- a/examples/plugins/csv/pom.xml +++ b/examples/plugins/csv/pom.xml @@ -9,7 +9,7 @@ com.helger.jcodemodel.examples.plugin csv - JCodeModel CSV Plugin Example + JCodeModel Example Generator CSV demonstrates and validates the usage of the jcodemodel plugin alongside the CSV generator @@ -61,13 +61,14 @@ generate-source + com.helger.jcodemodel.examples.plugin.csv.resolve - p com.helger.jcodemodel.examples.plugin.csv.resolve,,,get - com.helger.jcodemodel.examples.plugin.csv.resolve.Parent,children,Child[],set,private - com.helger.jcodemodel.examples.plugin.csv.resolve.Child,parent,Parent,private,set - com.helger.jcodemodel.examples.plugin.csv.resolve.Imported,,,set - com.helger.jcodemodel.examples.plugin.csv.resolve.Imported,model,com.helger.jcodemodel.JCodeModel,private - com.helger.jcodemodel.examples.plugin.csv.resolve.Imported,modelArr,com.helger.jcodemodel.JCodeModel[],private + p .,,,get + Parent,children,Child[],set,private + Child,parent,Parent,private,set + Imported,,,set + Imported,model,com.helger.jcodemodel.JCodeModel,private + Imported,modelArr,com.helger.jcodemodel.JCodeModel[],private @@ -78,10 +79,11 @@ generate-source + com.helger.jcodemodel.examples.plugin.csv.lastupdated - com.helger.jcodemodel.examples.plugin.csv.lastupdated.LastUpdated,,,set,get,private,lastupdated - com.helger.jcodemodel.examples.plugin.csv.lastupdated.LastUpdated,i,int - com.helger.jcodemodel.examples.plugin.csv.lastupdated.LastUpdated,s,string + LastUpdated,,,set,get,private,lastupdated + LastUpdated,i,int + LastUpdated,s,string @@ -91,16 +93,17 @@ generate-source + com.helger.jcodemodel.examples.plugin.csv.redirect - com.helger.jcodemodel.examples.plugin.csv.redirect.ABC,,,private,get,set - com.helger.jcodemodel.examples.plugin.csv.redirect.ABC,a,int - com.helger.jcodemodel.examples.plugin.csv.redirect.ABC,b,bool - com.helger.jcodemodel.examples.plugin.csv.redirect.ABC,c,char - com.helger.jcodemodel.examples.plugin.csv.redirect.Redirected,,,private,redirect - com.helger.jcodemodel.examples.plugin.csv.redirect.Redirected,abc,ABC,set - com.helger.jcodemodel.examples.plugin.csv.redirect.Redirected,jCatchBlock,com.helger.jcodemodel.JCatchBlock,set + ABC,,,private,get,set + ABC,a,int + ABC,b,bool + ABC,c,char + Redirected,,,private,redirect + Redirected,abc,ABC,set + Redirected,jCatchBlock,com.helger.jcodemodel.JCatchBlock,set - com.helger.jcodemodel.examples.plugin.csv.redirect.ClassRedirect,e,java.lang.ArrayIndexOutOfBoundsException,set,redirect + ClassRedirect,e,java.lang.ArrayIndexOutOfBoundsException,set,redirect @@ -110,39 +113,41 @@ generate-source + com.helger.jcodemodel.examples.plugin.csv - p com.helger.jcodemodel.examples.plugin.csv.inherit,,,set,get,private - com.helger.jcodemodel.examples.plugin.csv.inherit.Point,x,int - com.helger.jcodemodel.examples.plugin.csv.inherit.Point,y,int - com.helger.jcodemodel.examples.plugin.csv.inherit.City,,Point - com.helger.jcodemodel.examples.plugin.csv.inherit.City,name,string - com.helger.jcodemodel.examples.plugin.csv.inherit.City,zip,int + p inherit,,,set,get,private + inherit.Point,x,int + inherit.Point,y,int + inherit.City,,Point + inherit.City,name,string + inherit.City,zip,int - com.helger.jcodemodel.examples.plugin.csv.inherit.Dated,,java.io.Serializable,lastupdated - com.helger.jcodemodel.examples.plugin.csv.inherit.Dated,created,date, final, getter + inherit.Dated,,java.io.Serializable,lastupdated + inherit.Dated,created,date, final, getter - final + immutable generate-source + com.helger.jcodemodel.examples.plugin.csv.immutable - p com.helger.jcodemodel.examples.plugin.csv.immutable,,,set,get,private,final - com.helger.jcodemodel.examples.plugin.csv.immutable.Animal,dob,date - com.helger.jcodemodel.examples.plugin.csv.immutable.Animal,id,long - com.helger.jcodemodel.examples.plugin.csv.immutable.Animal,name,string,mutable - com.helger.jcodemodel.examples.plugin.csv.immutable.Animal,parents,Animal[] - com.helger.jcodemodel.examples.plugin.csv.immutable.Animal,children,Animal, list - com.helger.jcodemodel.examples.plugin.csv.immutable.Dog,,Animal - com.helger.jcodemodel.examples.plugin.csv.immutable.Dog,species,string - com.helger.jcodemodel.examples.plugin.csv.immutable.Dog,master,string,mutable + p .,,,set,get,private,final + Animal,dob,date + Animal,id,long + Animal,name,string,mutable + Animal,parents,Animal[] + Animal,children,Animal list + Dog,,Animal + Dog,species,string + Dog,master,string,mutable - com.helger.jcodemodel.examples.plugin.csv.immutable.WeirdReference,,java.lang.ref.WeakReference,get,set - com.helger.jcodemodel.examples.plugin.csv.immutable.WeirdReference,created,date,final - com.helger.jcodemodel.examples.plugin.csv.immutable.WeirdReference, visible , boolean, mutable + WeirdReference,,java.lang.ref.WeakReference,get,set + WeirdReference,created,date,final + WeirdReference, visible , boolean, mutable diff --git a/examples/plugins/csv/src/generated/java/com/helger/jcodemodel/examples/plugin/csv/redirect/ClassRedirect.java b/examples/plugins/csv/src/generated/java/com/helger/jcodemodel/examples/plugin/csv/redirect/ClassRedirect.java index dedcd3fc..d552838c 100644 --- a/examples/plugins/csv/src/generated/java/com/helger/jcodemodel/examples/plugin/csv/redirect/ClassRedirect.java +++ b/examples/plugins/csv/src/generated/java/com/helger/jcodemodel/examples/plugin/csv/redirect/ClassRedirect.java @@ -13,20 +13,8 @@ public void setE(ArrayIndexOutOfBoundsException e) { this.e = e; } - public void printStackTrace(PrintWriter arg0) { - e.printStackTrace(arg0); - } - - public void printStackTrace() { - e.printStackTrace(); - } - - public void printStackTrace(PrintStream arg0) { - e.printStackTrace(arg0); - } - - public StackTraceElement[] getStackTrace() { - return e.getStackTrace(); + public void addSuppressed(Throwable arg0) { + e.addSuppressed(arg0); } public Throwable fillInStackTrace() { @@ -37,27 +25,39 @@ public Throwable getCause() { return e.getCause(); } - public Throwable initCause(Throwable arg0) { - return e.initCause(arg0); + public String getLocalizedMessage() { + return e.getLocalizedMessage(); } public String getMessage() { return e.getMessage(); } + public StackTraceElement[] getStackTrace() { + return e.getStackTrace(); + } + public Throwable[] getSuppressed() { return e.getSuppressed(); } - public String getLocalizedMessage() { - return e.getLocalizedMessage(); + public Throwable initCause(Throwable arg0) { + return e.initCause(arg0); } - public void setStackTrace(StackTraceElement[] arg0) { - e.setStackTrace(arg0); + public void printStackTrace() { + e.printStackTrace(); } - public void addSuppressed(Throwable arg0) { - e.addSuppressed(arg0); + public void printStackTrace(PrintStream arg0) { + e.printStackTrace(arg0); + } + + public void printStackTrace(PrintWriter arg0) { + e.printStackTrace(arg0); + } + + public void setStackTrace(StackTraceElement[] arg0) { + e.setStackTrace(arg0); } } diff --git a/examples/plugins/csv/src/generated/java/com/helger/jcodemodel/examples/plugin/csv/redirect/Redirected.java b/examples/plugins/csv/src/generated/java/com/helger/jcodemodel/examples/plugin/csv/redirect/Redirected.java index e054527c..effab5c9 100644 --- a/examples/plugins/csv/src/generated/java/com/helger/jcodemodel/examples/plugin/csv/redirect/Redirected.java +++ b/examples/plugins/csv/src/generated/java/com/helger/jcodemodel/examples/plugin/csv/redirect/Redirected.java @@ -48,10 +48,18 @@ public char getC() { return abc.getC(); } + public JBlock body() { + return jCatchBlock.body(); + } + public AbstractJClass exception() { return jCatchBlock.exception(); } + public void generate(IJFormatter arg0) { + jCatchBlock.generate(arg0); + } + public JVar param() { return jCatchBlock.param(); } @@ -59,12 +67,4 @@ public JVar param() { public JVar param(String arg0) { return jCatchBlock.param(arg0); } - - public JBlock body() { - return jCatchBlock.body(); - } - - public void generate(IJFormatter arg0) { - jCatchBlock.generate(arg0); - } } diff --git a/examples/plugins/helloworld/pom.xml b/examples/plugins/helloworld/pom.xml index b1d8e23f..bba1be7f 100644 --- a/examples/plugins/helloworld/pom.xml +++ b/examples/plugins/helloworld/pom.xml @@ -9,7 +9,7 @@ com.helger.jcodemodel.examples.plugin helloworld - JCodeModel HelloWorld Example + JCodeModel Example Generator HelloWorld demonstrates and validates the usage of the jcodemodel plugin alongside the helloworld generator diff --git a/examples/plugins/json/pom.xml b/examples/plugins/json/pom.xml new file mode 100644 index 00000000..321cbac9 --- /dev/null +++ b/examples/plugins/json/pom.xml @@ -0,0 +1,133 @@ + + + 4.0.0 + + com.helger.jcodemodel.examples + plugins + 4.0.1-SNAPSHOT + + com.helger.jcodemodel.examples.plugin + json + JCodeModel Example Generator JSON + demonstrates and validates the usage of the jcodemodel plugin alongside the Json generator + + + + + com.helger.jcodemodel + jcodemodel-maven-plugin + + + basic + + generate-source + + + com.helger.jcodemodel.examples.plugin.json.basic + +{ + "package":[ + "get", + "set" + ], + "A":{ + "var":{ + "a":{ + "class":"int", + "options":[ + "private", + "final" + ] + } + } + }, + "B":{ + "extends":"A", + "var":{ + "b":{ + "class":"int", + "options":[ + "private" + ] + } + } + }, + "C":{ + "var":{ + "redirect":{ + "class":"B", + "options":[ + "private", + "redirect" + ] + } + } + } +} + + + + + + + com.helger.jcodemodel.plugin.generators + json + ${project.version} + + + + + maven-clean-plugin + + + + src/generated/java + + + + + + + org.codehaus.mojo + build-helper-maven-plugin + 3.6.1 + + + add-source + generate-sources + + add-source + + + + src/generated/java + + + + + + + + + + + + com.helger.jcodemodel.examples.plugin + helloworld + ${project.version} + true + + + + junit + junit + test + + + org.slf4j + slf4j-simple + test + + + diff --git a/examples/plugins/json/src/generated/java/com/helger/jcodemodel/examples/plugin/json/basic/A.java b/examples/plugins/json/src/generated/java/com/helger/jcodemodel/examples/plugin/json/basic/A.java new file mode 100644 index 00000000..e23505a8 --- /dev/null +++ b/examples/plugins/json/src/generated/java/com/helger/jcodemodel/examples/plugin/json/basic/A.java @@ -0,0 +1,16 @@ +package com.helger.jcodemodel.examples.plugin.json.basic; + +public class A { + private final int a; + + public A(int a) { + this.a = a; + } + + /** + * @return the {@link #a} + */ + public int getA() { + return a; + } +} diff --git a/examples/plugins/json/src/generated/java/com/helger/jcodemodel/examples/plugin/json/basic/B.java b/examples/plugins/json/src/generated/java/com/helger/jcodemodel/examples/plugin/json/basic/B.java new file mode 100644 index 00000000..a62ff3c2 --- /dev/null +++ b/examples/plugins/json/src/generated/java/com/helger/jcodemodel/examples/plugin/json/basic/B.java @@ -0,0 +1,25 @@ +package com.helger.jcodemodel.examples.plugin.json.basic; + +public class B + extends A +{ + private int b; + + public B(int a) { + super(a); + } + + /** + * set the {@link #b} + */ + public void setB(int b) { + this.b = b; + } + + /** + * @return the {@link #b} + */ + public int getB() { + return b; + } +} diff --git a/examples/plugins/json/src/generated/java/com/helger/jcodemodel/examples/plugin/json/basic/C.java b/examples/plugins/json/src/generated/java/com/helger/jcodemodel/examples/plugin/json/basic/C.java new file mode 100644 index 00000000..34353c50 --- /dev/null +++ b/examples/plugins/json/src/generated/java/com/helger/jcodemodel/examples/plugin/json/basic/C.java @@ -0,0 +1,27 @@ +package com.helger.jcodemodel.examples.plugin.json.basic; + +public class C { + private B redirect; + + /** + * set the {@link #redirect} + */ + public void setRedirect(B redirect) { + this.redirect = redirect; + } + + /** + * @return the {@link #redirect} + */ + public B getRedirect() { + return redirect; + } + + public void setB(int b) { + redirect.setB(b); + } + + public int getB() { + return redirect.getB(); + } +} diff --git a/examples/plugins/pom.xml b/examples/plugins/pom.xml index 843eb99d..1a4b2fee 100644 --- a/examples/plugins/pom.xml +++ b/examples/plugins/pom.xml @@ -7,14 +7,16 @@ examples 4.0.1-SNAPSHOT - com.helger.jcodemodel.examples + com.helger.jcodemodel.examples plugins pom - JCodeModel Plugins Examples Pom + JCodeModel Examples Plugins Pom - helloworld - csv + csv + helloworld + json + yaml POM module for all the plugin examples diff --git a/examples/plugins/yaml/pom.xml b/examples/plugins/yaml/pom.xml new file mode 100644 index 00000000..bd2b3357 --- /dev/null +++ b/examples/plugins/yaml/pom.xml @@ -0,0 +1,109 @@ + + + 4.0.0 + + com.helger.jcodemodel.examples + plugins + 4.0.1-SNAPSHOT + + com.helger.jcodemodel.examples.plugin + yaml + JCodeModel Example Generator YAML + demonstrates and validates the usage of the jcodemodel plugin alongside the YAML generator + + + + + com.helger.jcodemodel + jcodemodel-maven-plugin + + + basic + + generate-source + + + sourceBasic.yaml + + + + concrete + + generate-source + + + sourceConcrete.yaml + com.helger.jcodemodel.examples.plugin.yaml.concrete + + LinkedList + LinkedHashMap + LinkedHashSet + + + + + references + + generate-source + + + com.helger.jcodemodel.examples.plugin.yaml.references + sourceReferences.yaml + + + + + + com.helger.jcodemodel.plugin.generators + yaml + ${project.version} + + + + + maven-clean-plugin + + + + src/generated/java + + + + + + + org.codehaus.mojo + build-helper-maven-plugin + 3.6.1 + + + add-source + generate-sources + + add-source + + + + src/generated/java + + + + + + + + + + + junit + junit + test + + + org.slf4j + slf4j-simple + test + + + diff --git a/examples/plugins/yaml/sourceBasic.yaml b/examples/plugins/yaml/sourceBasic.yaml new file mode 100644 index 00000000..41a134c0 --- /dev/null +++ b/examples/plugins/yaml/sourceBasic.yaml @@ -0,0 +1,52 @@ +# yaml is stored in file as the pom tabs can be changed by git, which is not allowed by yaml format. + +com.helger.jcodemodel.examples.plugin.yaml.basic: + package: # we add getters and setters on all field of the package + - get + - set + + A: # class A with an int. It is final so no setter actually created, and constructor added + var: + uuid: + class: long + options: + - private + - final + + B: # extends A so add a constructor + extends: A + var: + nbChildren: + class: int + options: + - private + distances: # a matrix of doubles + class: double [] [] + options: + - private + + C: + var: + redir: # all public methods exposed in B are exposed in that class and redirect to the field + class: B + options: + - private + - redirect + list: + class: obj list list set + + Empty1: # empty class. Needs the class field with at least one empty value + class: + - + + Empty2: # empty class. is a class because extends is present + extends: "" + + ListSon: + extends: "object list list" + class: + - noget + - noset + var: + listf: + class: "object list list" diff --git a/examples/plugins/yaml/sourceConcrete.yaml b/examples/plugins/yaml/sourceConcrete.yaml new file mode 100644 index 00000000..5643cf98 --- /dev/null +++ b/examples/plugins/yaml/sourceConcrete.yaml @@ -0,0 +1,14 @@ +# yaml is stored in file as the pom tabs can be changed by git, which is not allowed by yaml format. + +package: # we add getters and setters on all field of the package + - get + - set + +ConcreteList: + extends: "object list list" + +ConcreteMap: + extends: "string map" + +ConcreteSet: + extends: "object list set" diff --git a/examples/plugins/yaml/sourceReferences.yaml b/examples/plugins/yaml/sourceReferences.yaml new file mode 100644 index 00000000..a6f3c986 --- /dev/null +++ b/examples/plugins/yaml/sourceReferences.yaml @@ -0,0 +1,13 @@ +# yaml is stored in file as the pom tabs can be changed by git, which is not allowed by yaml format. + +package: # we add getters and setters on all field of the package + - get + - set + - private + +WeakRefTest: + var: + hash: + class: string + options: + - weakref \ No newline at end of file diff --git a/examples/plugins/yaml/src/generated/java/com/helger/jcodemodel/examples/plugin/yaml/basic/A.java b/examples/plugins/yaml/src/generated/java/com/helger/jcodemodel/examples/plugin/yaml/basic/A.java new file mode 100644 index 00000000..9e427c9a --- /dev/null +++ b/examples/plugins/yaml/src/generated/java/com/helger/jcodemodel/examples/plugin/yaml/basic/A.java @@ -0,0 +1,16 @@ +package com.helger.jcodemodel.examples.plugin.yaml.basic; + +public class A { + private final long uuid; + + public A(long uuid) { + this.uuid = uuid; + } + + /** + * @return the {@link #uuid} + */ + public long getUuid() { + return uuid; + } +} diff --git a/examples/plugins/yaml/src/generated/java/com/helger/jcodemodel/examples/plugin/yaml/basic/B.java b/examples/plugins/yaml/src/generated/java/com/helger/jcodemodel/examples/plugin/yaml/basic/B.java new file mode 100644 index 00000000..c9499404 --- /dev/null +++ b/examples/plugins/yaml/src/generated/java/com/helger/jcodemodel/examples/plugin/yaml/basic/B.java @@ -0,0 +1,40 @@ +package com.helger.jcodemodel.examples.plugin.yaml.basic; + +public class B + extends A +{ + private int nbChildren; + private double[][] distances; + + public B(long uuid) { + super(uuid); + } + + /** + * set the {@link #nbChildren} + */ + public void setNbChildren(int nbChildren) { + this.nbChildren = nbChildren; + } + + /** + * @return the {@link #nbChildren} + */ + public int getNbChildren() { + return nbChildren; + } + + /** + * set the {@link #distances} + */ + public void setDistances(double[][] distances) { + this.distances = distances; + } + + /** + * @return the {@link #distances} + */ + public double[][] getDistances() { + return distances; + } +} diff --git a/examples/plugins/yaml/src/generated/java/com/helger/jcodemodel/examples/plugin/yaml/basic/C.java b/examples/plugins/yaml/src/generated/java/com/helger/jcodemodel/examples/plugin/yaml/basic/C.java new file mode 100644 index 00000000..eefca815 --- /dev/null +++ b/examples/plugins/yaml/src/generated/java/com/helger/jcodemodel/examples/plugin/yaml/basic/C.java @@ -0,0 +1,53 @@ +package com.helger.jcodemodel.examples.plugin.yaml.basic; + +import java.util.List; +import java.util.Set; + +public class C { + private B redir; + public Set>> list; + + /** + * set the {@link #redir} + */ + public void setRedir(B redir) { + this.redir = redir; + } + + /** + * @return the {@link #redir} + */ + public B getRedir() { + return redir; + } + + /** + * set the {@link #list} + */ + public void setList(Set>> list) { + this.list = list; + } + + /** + * @return the {@link #list} + */ + public Set>> getList() { + return list; + } + + public void setNbChildren(int nbChildren) { + redir.setNbChildren(nbChildren); + } + + public int getNbChildren() { + return redir.getNbChildren(); + } + + public void setDistances(double[][] distances) { + redir.setDistances(distances); + } + + public double[][] getDistances() { + return redir.getDistances(); + } +} diff --git a/examples/plugins/yaml/src/generated/java/com/helger/jcodemodel/examples/plugin/yaml/basic/Empty1.java b/examples/plugins/yaml/src/generated/java/com/helger/jcodemodel/examples/plugin/yaml/basic/Empty1.java new file mode 100644 index 00000000..acf6b3d8 --- /dev/null +++ b/examples/plugins/yaml/src/generated/java/com/helger/jcodemodel/examples/plugin/yaml/basic/Empty1.java @@ -0,0 +1,4 @@ +package com.helger.jcodemodel.examples.plugin.yaml.basic; + +public class Empty1 { +} diff --git a/examples/plugins/yaml/src/generated/java/com/helger/jcodemodel/examples/plugin/yaml/basic/Empty2.java b/examples/plugins/yaml/src/generated/java/com/helger/jcodemodel/examples/plugin/yaml/basic/Empty2.java new file mode 100644 index 00000000..482a15e1 --- /dev/null +++ b/examples/plugins/yaml/src/generated/java/com/helger/jcodemodel/examples/plugin/yaml/basic/Empty2.java @@ -0,0 +1,4 @@ +package com.helger.jcodemodel.examples.plugin.yaml.basic; + +public class Empty2 { +} diff --git a/examples/plugins/yaml/src/generated/java/com/helger/jcodemodel/examples/plugin/yaml/basic/ListSon.java b/examples/plugins/yaml/src/generated/java/com/helger/jcodemodel/examples/plugin/yaml/basic/ListSon.java new file mode 100644 index 00000000..828bdce5 --- /dev/null +++ b/examples/plugins/yaml/src/generated/java/com/helger/jcodemodel/examples/plugin/yaml/basic/ListSon.java @@ -0,0 +1,10 @@ +package com.helger.jcodemodel.examples.plugin.yaml.basic; + +import java.util.ArrayList; +import java.util.List; + +public class ListSon + extends ArrayList> +{ + public List> listf; +} diff --git a/examples/plugins/yaml/src/generated/java/com/helger/jcodemodel/examples/plugin/yaml/concrete/ConcreteList.java b/examples/plugins/yaml/src/generated/java/com/helger/jcodemodel/examples/plugin/yaml/concrete/ConcreteList.java new file mode 100644 index 00000000..92ed315e --- /dev/null +++ b/examples/plugins/yaml/src/generated/java/com/helger/jcodemodel/examples/plugin/yaml/concrete/ConcreteList.java @@ -0,0 +1,8 @@ +package com.helger.jcodemodel.examples.plugin.yaml.concrete; + +import java.util.LinkedList; + +public class ConcreteList + extends LinkedList> +{ +} diff --git a/examples/plugins/yaml/src/generated/java/com/helger/jcodemodel/examples/plugin/yaml/concrete/ConcreteMap.java b/examples/plugins/yaml/src/generated/java/com/helger/jcodemodel/examples/plugin/yaml/concrete/ConcreteMap.java new file mode 100644 index 00000000..cb9c71ea --- /dev/null +++ b/examples/plugins/yaml/src/generated/java/com/helger/jcodemodel/examples/plugin/yaml/concrete/ConcreteMap.java @@ -0,0 +1,8 @@ +package com.helger.jcodemodel.examples.plugin.yaml.concrete; + +import java.util.LinkedHashMap; + +public class ConcreteMap + extends LinkedHashMap +{ +} diff --git a/examples/plugins/yaml/src/generated/java/com/helger/jcodemodel/examples/plugin/yaml/concrete/ConcreteSet.java b/examples/plugins/yaml/src/generated/java/com/helger/jcodemodel/examples/plugin/yaml/concrete/ConcreteSet.java new file mode 100644 index 00000000..1041614b --- /dev/null +++ b/examples/plugins/yaml/src/generated/java/com/helger/jcodemodel/examples/plugin/yaml/concrete/ConcreteSet.java @@ -0,0 +1,9 @@ +package com.helger.jcodemodel.examples.plugin.yaml.concrete; + +import java.util.LinkedHashSet; +import java.util.LinkedList; + +public class ConcreteSet + extends LinkedHashSet> +{ +} diff --git a/examples/plugins/yaml/src/generated/java/com/helger/jcodemodel/examples/plugin/yaml/references/WeakRefTest.java b/examples/plugins/yaml/src/generated/java/com/helger/jcodemodel/examples/plugin/yaml/references/WeakRefTest.java new file mode 100644 index 00000000..d6f58a08 --- /dev/null +++ b/examples/plugins/yaml/src/generated/java/com/helger/jcodemodel/examples/plugin/yaml/references/WeakRefTest.java @@ -0,0 +1,21 @@ +package com.helger.jcodemodel.examples.plugin.yaml.references; + +import java.lang.ref.WeakReference; + +public class WeakRefTest { + private WeakReference hash; + + /** + * set the {@link #hash} + */ + public void setHash(String hash) { + this.hash = new WeakReference(hash); + } + + /** + * @return the {@link #hash} + */ + public String getHash() { + return hash.get(); + } +} diff --git a/examples/plugins/yaml/src/test/java/com/helger/jcodemodel/examples/plugin/yaml/YamlTest.java b/examples/plugins/yaml/src/test/java/com/helger/jcodemodel/examples/plugin/yaml/YamlTest.java new file mode 100644 index 00000000..cb391749 --- /dev/null +++ b/examples/plugins/yaml/src/test/java/com/helger/jcodemodel/examples/plugin/yaml/YamlTest.java @@ -0,0 +1,50 @@ +package com.helger.jcodemodel.examples.plugin.yaml; + +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.LinkedList; + +import org.junit.Assert; +import org.junit.Test; + +import com.helger.jcodemodel.examples.plugin.yaml.basic.A; +import com.helger.jcodemodel.examples.plugin.yaml.basic.B; +import com.helger.jcodemodel.examples.plugin.yaml.basic.C; +import com.helger.jcodemodel.examples.plugin.yaml.basic.Empty1; +import com.helger.jcodemodel.examples.plugin.yaml.basic.Empty2; +import com.helger.jcodemodel.examples.plugin.yaml.concrete.ConcreteList; +import com.helger.jcodemodel.examples.plugin.yaml.concrete.ConcreteMap; +import com.helger.jcodemodel.examples.plugin.yaml.concrete.ConcreteSet; + +public class YamlTest { + + @Test + public void testBasic() { + A a = new A(25L); + Assert.assertEquals(25L, a.getUuid()); + + B b = new B(28L); + b.setNbChildren(30); + Assert.assertEquals(28L, b.getUuid()); + Assert.assertEquals(30, b.getNbChildren()); + + C c = new C(); + c.setRedir(b); + Assert.assertEquals(30, c.getNbChildren()); + double[][] distances = new double[2][]; + c.setDistances(distances); + Assert.assertSame(distances, b.getDistances()); + + new Empty1(); + new Empty2(); + } + + @Test + public void testConcrete() { + // just check that the implementation are indeed + Assert.assertTrue(new ConcreteList() instanceof LinkedList); + Assert.assertTrue(new ConcreteMap() instanceof LinkedHashMap); + Assert.assertTrue(new ConcreteSet() instanceof LinkedHashSet); + } + +} diff --git a/plugin/generators/csv/pom.xml b/plugin/generators/csv/pom.xml index e96310ab..77eb2704 100644 --- a/plugin/generators/csv/pom.xml +++ b/plugin/generators/csv/pom.xml @@ -9,6 +9,6 @@ com.helger.jcodemodel.plugin.generators csv - JCodeModel CSV Generator + JCodeModel Generator CSV generates a structure tree from a csv file diff --git a/plugin/generators/csv/src/main/java/com/helger/jcodemodel/plugin/generators/csv/CSVGenerator.java b/plugin/generators/csv/src/main/java/com/helger/jcodemodel/plugin/generators/csv/CSVGenerator.java index a11fcd62..e5600665 100644 --- a/plugin/generators/csv/src/main/java/com/helger/jcodemodel/plugin/generators/csv/CSVGenerator.java +++ b/plugin/generators/csv/src/main/java/com/helger/jcodemodel/plugin/generators/csv/CSVGenerator.java @@ -9,11 +9,10 @@ import com.helger.jcodemodel.plugin.maven.generators.FlatStructureGenerator; import com.helger.jcodemodel.plugin.maven.generators.JCMGen; -import com.helger.jcodemodel.plugin.maven.generators.flatstruct.FieldConstruct; import com.helger.jcodemodel.plugin.maven.generators.flatstruct.FieldOptions; -import com.helger.jcodemodel.plugin.maven.generators.flatstruct.FieldVisibility; import com.helger.jcodemodel.plugin.maven.generators.flatstruct.FlatStructRecord; import com.helger.jcodemodel.plugin.maven.generators.flatstruct.FlatStructRecord.ClassCreation; +import com.helger.jcodemodel.plugin.maven.generators.flatstruct.FlatStructRecord.Encapsulated; import com.helger.jcodemodel.plugin.maven.generators.flatstruct.FlatStructRecord.PackageCreation; import com.helger.jcodemodel.plugin.maven.generators.flatstruct.FlatStructRecord.SimpleField; @@ -50,39 +49,16 @@ protected FlatStructRecord convertLine(String line) { // find the type specified, if any, and array depth - String fieldClassName = null; - int arrayDepth = 0; + + Encapsulated ec = null; if (spl.length > 2) { - fieldClassName = spl[2].trim(); - while (fieldClassName.endsWith("[]")) { - arrayDepth++; - fieldClassName = fieldClassName.replaceFirst("\\[\\]", "").trim(); - } - } - if (fieldClassName != null && fieldClassName.isBlank()) { - fieldClassName = null; + ec = Encapsulated.parse(spl[2]); } FieldOptions options = new FieldOptions(); if (spl.length >= 4) { for (int i = 3; i < spl.length; i++) { - String optStr = spl[i]; - if (optStr == null || optStr.isBlank()) { - continue; - } else { - optStr=optStr.trim(); - } - FieldVisibility fv = FieldVisibility.of(optStr); - if (fv != null) { - fv.apply(options); - } else { - FieldConstruct fa = FieldConstruct.of(optStr); - if (fa == null) { - throw new UnsupportedOperationException("can't deduce option from " + optStr); - } else { - fa.apply(options); - } - } + applyToFieldOptions(spl[i], options); } } @@ -91,10 +67,10 @@ protected FlatStructRecord convertLine(String line) { if (className.contains(" ")) { return new PackageCreation(className.replaceAll(".* ", ""), options); } else { - return new ClassCreation(className, fieldClassName, options); + return new ClassCreation(className, ec, options); } } else { - return new SimpleField(className, fieldName, fieldClassName, arrayDepth, options); + return new SimpleField(className, fieldName, ec, options); } } diff --git a/plugin/generators/helloworld/pom.xml b/plugin/generators/helloworld/pom.xml index acd5406a..e637af4c 100644 --- a/plugin/generators/helloworld/pom.xml +++ b/plugin/generators/helloworld/pom.xml @@ -9,6 +9,6 @@ com.helger.jcodemodel.plugin.generators helloworld - JCodeModel HelloWorld Generator + JCodeModel Generator HelloWorld generates a simple class with a value diff --git a/plugin/generators/helloworld/src/main/java/com/helger/jcodemodel/plugin/generators/helloworld/HelloWorldGenerator.java b/plugin/generators/helloworld/src/main/java/com/helger/jcodemodel/plugin/generators/helloworld/HelloWorldGenerator.java index 3bf9a4d8..84e5c914 100644 --- a/plugin/generators/helloworld/src/main/java/com/helger/jcodemodel/plugin/generators/helloworld/HelloWorldGenerator.java +++ b/plugin/generators/helloworld/src/main/java/com/helger/jcodemodel/plugin/generators/helloworld/HelloWorldGenerator.java @@ -14,7 +14,8 @@ @JCMGen public class HelloWorldGenerator implements CodeModelBuilder { - protected String className = "com.helger.tests.helloworld.Hello"; + protected String rootPackage = "com.helger.tests.helloworld"; + protected String className = "Hello"; protected String value = "world"; @Override @@ -25,8 +26,18 @@ public void configure(Map params) { @Override public void build(JCodeModel model, InputStream source) throws JCodeModelException { - JDefinedClass cl = model._class(className); + JDefinedClass cl = model._class(expandClassName(className)); cl.field(JMod.PUBLIC, model._ref(String.class), "value", JExpr.lit(value)); } + @Override + public void setRootPackage(String rootPackage) { + this.rootPackage = rootPackage; + } + + @Override + public String getRootPackage() { + return rootPackage; + } + } diff --git a/plugin/generators/json/pom.xml b/plugin/generators/json/pom.xml new file mode 100644 index 00000000..5b860261 --- /dev/null +++ b/plugin/generators/json/pom.xml @@ -0,0 +1,21 @@ + + + 4.0.0 + + com.helger.jcodemodel.plugin + generators + 4.0.1-SNAPSHOT + + com.helger.jcodemodel.plugin.generators + json + JCodeModel Generator JSON + generates a structure tree from a json file + + + com.fasterxml.jackson.core + jackson-databind + 2.20.0 + + + diff --git a/plugin/generators/json/src/main/java/com/helger/jcodemodel/plugin/generators/json/JsonGenerator.java b/plugin/generators/json/src/main/java/com/helger/jcodemodel/plugin/generators/json/JsonGenerator.java new file mode 100644 index 00000000..39d4666b --- /dev/null +++ b/plugin/generators/json/src/main/java/com/helger/jcodemodel/plugin/generators/json/JsonGenerator.java @@ -0,0 +1,86 @@ +package com.helger.jcodemodel.plugin.generators.json; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Map.Entry; +import java.util.stream.Stream; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.helger.jcodemodel.plugin.generators.json.parser.JsonField; +import com.helger.jcodemodel.plugin.generators.json.parser.JsonPackage; +import com.helger.jcodemodel.plugin.maven.generators.FlatStructureGenerator; +import com.helger.jcodemodel.plugin.maven.generators.JCMGen; +import com.helger.jcodemodel.plugin.maven.generators.flatstruct.FieldOptions; +import com.helger.jcodemodel.plugin.maven.generators.flatstruct.FlatStructRecord; +import com.helger.jcodemodel.plugin.maven.generators.flatstruct.FlatStructRecord.ClassCreation; +import com.helger.jcodemodel.plugin.maven.generators.flatstruct.FlatStructRecord.Encapsulated; +import com.helger.jcodemodel.plugin.maven.generators.flatstruct.FlatStructRecord.PackageCreation; +import com.helger.jcodemodel.plugin.maven.generators.flatstruct.FlatStructRecord.SimpleField; + +@JCMGen +public class JsonGenerator extends FlatStructureGenerator { + + @Override + protected Stream loadSource(InputStream source) { + try { + return visitPackage(load(source), null); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + protected JsonPackage load(InputStream source) throws IOException { + ObjectMapper mapper = new ObjectMapper(); + return mapper.readerFor(JsonPackage.class).readValue(source); + } + + protected Stream visitPackage(JsonPackage pck, String path) { + System.err.println("visit package " + path); + Stream ret = Stream.empty(); + if (pck.isClassInfo()) { + if (pck.clazz != null || pck.parentClassName != null) { + FieldOptions options = new FieldOptions(); + if (pck.clazz != null) { + for (String optStr : pck.clazz) { + applyToFieldOptions(optStr, options); + } + } + ret = Stream.concat(ret, + Stream.of(new ClassCreation(path, Encapsulated.parse(pck.parentClassName), options))); + } + if (pck.fields != null) { + for (Entry e : pck.fields.entrySet()) { + ret = Stream.concat(ret, visitField(e.getValue(), path, e.getKey())); + } + } + } else { + if (pck.isPackageInfo()) { + FieldOptions options = new FieldOptions(); + if (pck.pck != null) { + for (String optStr : pck.pck) { + applyToFieldOptions(optStr, options); + } + } + ret = Stream.concat(ret, Stream.of(new PackageCreation(path, options))); + } + for (Entry e : pck.subPackages().entrySet()) { + String subPath = (path == null ? "" : path + ".") + e.getKey(); + ret = Stream.concat(ret, visitPackage(e.getValue(), subPath)); + } + + } + return ret; + } + + protected Stream visitField(JsonField field, String path, String fieldName) { + FieldOptions options = new FieldOptions(); + if (field.options != null) { + for (String optStr : field.options) { + applyToFieldOptions(optStr, options); + } + } + Encapsulated enc = Encapsulated.parse(field.type); + return Stream.of(new SimpleField(path, fieldName, enc, options)); + } + +} diff --git a/plugin/generators/json/src/main/java/com/helger/jcodemodel/plugin/generators/json/parser/JsonField.java b/plugin/generators/json/src/main/java/com/helger/jcodemodel/plugin/generators/json/parser/JsonField.java new file mode 100644 index 00000000..f87041c4 --- /dev/null +++ b/plugin/generators/json/src/main/java/com/helger/jcodemodel/plugin/generators/json/parser/JsonField.java @@ -0,0 +1,15 @@ +package com.helger.jcodemodel.plugin.generators.json.parser; + +import java.util.ArrayList; +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class JsonField { + + @JsonProperty("class") + public String type; + + public List options = new ArrayList<>(); + +} diff --git a/plugin/generators/json/src/main/java/com/helger/jcodemodel/plugin/generators/json/parser/JsonPackage.java b/plugin/generators/json/src/main/java/com/helger/jcodemodel/plugin/generators/json/parser/JsonPackage.java new file mode 100644 index 00000000..03ff4c52 --- /dev/null +++ b/plugin/generators/json/src/main/java/com/helger/jcodemodel/plugin/generators/json/parser/JsonPackage.java @@ -0,0 +1,54 @@ +package com.helger.jcodemodel.plugin.generators.json.parser; + +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * can be a package, a class if no package + */ +public class JsonPackage { + + @JsonProperty("var") + public LinkedHashMap fields = new LinkedHashMap<>(); + + @JsonProperty("package") + public List pck = null; + + @JsonProperty("class") + public List clazz = null; + + @JsonProperty("extends") + public String parentClassName = null; + + private LinkedHashMap subPackages = new LinkedHashMap<>(); + + @JsonAnyGetter + public Map subPackages() { + return subPackages; + } + + @JsonAnySetter + public void setPackage(String name, JsonPackage pck) { + subPackages.put(name, pck); + } + + /** + * @return true if this requires to build a class + */ + public boolean isClassInfo() { + return clazz != null || fields != null && !fields.isEmpty() || parentClassName != null; + } + + /** + * @return true if this has package-specific information that need to be handled + */ + public boolean isPackageInfo() { + return pck != null; + } + +} diff --git a/plugin/generators/pom.xml b/plugin/generators/pom.xml index 747a19bf..03151029 100644 --- a/plugin/generators/pom.xml +++ b/plugin/generators/pom.xml @@ -10,10 +10,12 @@ com.helger.jcodemodel.plugin generators pom - JCodeModel Plugin Generators Pom + JCodeModel Generators Pom - helloworld csv + helloworld + json + yaml POM module for all the plugin-related codemodel generators diff --git a/plugin/generators/yaml/pom.xml b/plugin/generators/yaml/pom.xml new file mode 100644 index 00000000..8bac3af3 --- /dev/null +++ b/plugin/generators/yaml/pom.xml @@ -0,0 +1,26 @@ + + + 4.0.0 + + com.helger.jcodemodel.plugin + generators + 4.0.1-SNAPSHOT + + com.helger.jcodemodel.plugin.generators + yaml + JCodeModel Generator YAML + generates a structure tree from a yaml file + + + com.fasterxml.jackson.dataformat + jackson-dataformat-yaml + 2.20.0 + + + com.helger.jcodemodel.plugin.generators + json + ${project.version} + + + diff --git a/plugin/generators/yaml/src/main/java/com/helger/jcodemodel/plugin/generators/yaml/YamlGenerator.java b/plugin/generators/yaml/src/main/java/com/helger/jcodemodel/plugin/generators/yaml/YamlGenerator.java new file mode 100644 index 00000000..745fc21b --- /dev/null +++ b/plugin/generators/yaml/src/main/java/com/helger/jcodemodel/plugin/generators/yaml/YamlGenerator.java @@ -0,0 +1,22 @@ +package com.helger.jcodemodel.plugin.generators.yaml; + + +import java.io.IOException; +import java.io.InputStream; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; +import com.helger.jcodemodel.plugin.generators.json.JsonGenerator; +import com.helger.jcodemodel.plugin.generators.json.parser.JsonPackage; +import com.helger.jcodemodel.plugin.maven.generators.JCMGen; + +@JCMGen +public class YamlGenerator extends JsonGenerator { + + @Override + protected JsonPackage load(InputStream source) throws IOException { + ObjectMapper mapper = new ObjectMapper(new YAMLFactory()); + return mapper.readerFor(JsonPackage.class).readValue(source); + } + +} diff --git a/plugin/plugin/pom.xml b/plugin/plugin/pom.xml index 4c629039..206fb232 100644 --- a/plugin/plugin/pom.xml +++ b/plugin/plugin/pom.xml @@ -15,6 +15,11 @@ com.helger jcodemodel + + junit + junit + test + org.apache.maven maven-core @@ -33,6 +38,11 @@ 3.7.0 provided + + org.slf4j + slf4j-simple + test + diff --git a/plugin/plugin/src/main/java/com/helger/jcodemodel/plugin/maven/CodeModelBuilder.java b/plugin/plugin/src/main/java/com/helger/jcodemodel/plugin/maven/CodeModelBuilder.java index 93b1242d..354a147d 100644 --- a/plugin/plugin/src/main/java/com/helger/jcodemodel/plugin/maven/CodeModelBuilder.java +++ b/plugin/plugin/src/main/java/com/helger/jcodemodel/plugin/maven/CodeModelBuilder.java @@ -15,9 +15,10 @@ public interface CodeModelBuilder { /** * called by the plugin after creating the generator, with the plugin "params" - * configuration + * configuration. Override to handle generator-specific parameters */ - void configure(Map params); + default void configure(Map params) { + } /** * asking the generator to build a model. @@ -36,4 +37,19 @@ default void build(JCodeModel model) throws JCodeModelException { build(model, null); } + // local path expansion + + void setRootPackage(String rootPackage); + + String getRootPackage(); + + /** + * @param localPath class we want to create, eg "pck.MyClass" + * @return localpath prefixed by rootpackage and "." if needed. + */ + default String expandClassName(String localPath) { + String rootPackage = getRootPackage(); + return rootPackage == null || rootPackage.isBlank() ? localPath : rootPackage + "." + localPath; + } + } diff --git a/plugin/plugin/src/main/java/com/helger/jcodemodel/plugin/maven/GenerateSourceMojo.java b/plugin/plugin/src/main/java/com/helger/jcodemodel/plugin/maven/GenerateSourceMojo.java index 659e025d..2c51119b 100644 --- a/plugin/plugin/src/main/java/com/helger/jcodemodel/plugin/maven/GenerateSourceMojo.java +++ b/plugin/plugin/src/main/java/com/helger/jcodemodel/plugin/maven/GenerateSourceMojo.java @@ -40,6 +40,9 @@ public class GenerateSourceMojo extends AbstractMojo { @Parameter(property = "jcodemodel.outdir", defaultValue = "src/generated/java") private String outputDir; + @Parameter(property = "jcodemodel.rootpackage", defaultValue = "") + private String rootPackage; + /** * source of the data to transmit to the generator when building the model. can * be a url, a file. @@ -84,12 +87,17 @@ public void execute() throws MojoExecutionException, MojoFailureException { } getLog().info("Generator " + cmb.getClass().getCanonicalName() + " generates model into " + dir.getAbsolutePath() + " with params " + params); + + if (rootPackage != null && !rootPackage.isBlank()) { + cmb.setRootPackage(rootPackage); + } if (params != null) { cmb.configure(params); } + JCodeModel cm = new JCodeModel(); if (data != null && !data.isBlank() && source != null && !source.isBlank()) { - getLog().warn("discarding source param " + source + " as dat is already set"); + getLog().warn("discarding source param " + source + " as data is already set"); } InputStream source = data == null || data.isBlank() ? findSource() : new ByteArrayInputStream(data.getBytes()); try { diff --git a/plugin/plugin/src/main/java/com/helger/jcodemodel/plugin/maven/generators/FlatStructureGenerator.java b/plugin/plugin/src/main/java/com/helger/jcodemodel/plugin/maven/generators/FlatStructureGenerator.java index 79d47ad1..c619319d 100644 --- a/plugin/plugin/src/main/java/com/helger/jcodemodel/plugin/maven/generators/FlatStructureGenerator.java +++ b/plugin/plugin/src/main/java/com/helger/jcodemodel/plugin/maven/generators/FlatStructureGenerator.java @@ -2,11 +2,15 @@ import java.io.InputStream; import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.lang.reflect.Parameter; import java.time.Instant; +import java.util.AbstractMap.SimpleEntry; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -14,22 +18,51 @@ import java.util.Map.Entry; import java.util.Objects; import java.util.Set; +import java.util.stream.Collectors; import java.util.stream.Stream; import com.helger.jcodemodel.*; import com.helger.jcodemodel.exceptions.JCodeModelException; import com.helger.jcodemodel.plugin.maven.CodeModelBuilder; +import com.helger.jcodemodel.plugin.maven.generators.flatstruct.ConcreteTypes; +import com.helger.jcodemodel.plugin.maven.generators.flatstruct.FieldCanner; +import com.helger.jcodemodel.plugin.maven.generators.flatstruct.FieldOption; import com.helger.jcodemodel.plugin.maven.generators.flatstruct.FieldOptions; +import com.helger.jcodemodel.plugin.maven.generators.flatstruct.FieldVisibility; import com.helger.jcodemodel.plugin.maven.generators.flatstruct.FlatStructRecord; import com.helger.jcodemodel.plugin.maven.generators.flatstruct.FlatStructRecord.ClassCreation; +import com.helger.jcodemodel.plugin.maven.generators.flatstruct.FlatStructRecord.Encapsulated; +import com.helger.jcodemodel.plugin.maven.generators.flatstruct.FlatStructRecord.Encapsulation; import com.helger.jcodemodel.plugin.maven.generators.flatstruct.FlatStructRecord.FieldCreation; import com.helger.jcodemodel.plugin.maven.generators.flatstruct.FlatStructRecord.PackageCreation; import com.helger.jcodemodel.plugin.maven.generators.flatstruct.FlatStructRecord.SimpleField; +import com.helger.jcodemodel.plugin.maven.generators.flatstruct.canners.NoCanner; +import com.helger.jcodemodel.plugin.maven.generators.flatstruct.canners.reference.WeakReferenceCanner; public abstract class FlatStructureGenerator implements CodeModelBuilder { protected abstract Stream loadSource(InputStream source); + private String rootPackage = ""; + + @Override + public void setRootPackage(String rootPackage) { + this.rootPackage = rootPackage; + } + + @Override + public String getRootPackage() { + return rootPackage; + } + + protected ConcreteTypes concrete; + + @Override + public void configure(Map params) { + CodeModelBuilder.super.configure(params); + concrete = ConcreteTypes.from(params); + } + @Override public void build(JCodeModel model, InputStream source) throws JCodeModelException { List records = loadSource(source).toList(); @@ -42,7 +75,7 @@ public void build(JCodeModel model, InputStream source) throws JCodeModelExcepti } /** - * all the classes we created, by fully qualified name + * all the classes we created, by local name */ private Map definedClasses = new HashMap<>(); @@ -53,12 +86,12 @@ public void build(JCodeModel model, InputStream source) throws JCodeModelExcepti private Map> simpleDefinedClasses = new HashMap<>(); /** - * classes and package options, added as we create them. + * classes and package options stored by local name, added as we create them. */ private Map pathOptions = new HashMap<>(); /** - * fully qualified class name to the lastUpdated field + * fully qualified class name to their "lastUpdated" field */ private Map classLastUpdated = new HashMap<>(); @@ -69,11 +102,12 @@ public void build(JCodeModel model, InputStream source) throws JCodeModelExcepti protected void createClasses(JCodeModel model, List records) { for (FlatStructRecord rec : records) { if (rec instanceof ClassCreation cc) { - ensureClass(model, cc.fullyQualifiedClassName(), cc.options()); + ensureClass(model, cc.localName(), cc.options()); } else if (rec instanceof PackageCreation pc) { - pathOptions.put(pc.fullyQualifiedClassName(), pc.options()); + String localName = pc.localName() == null ? "" : pc.localName().replaceAll("^\\.", ""); + pathOptions.put(localName, pc.options()); } else if (rec instanceof FieldCreation fc) { - ensureClass(model, fc.fullyQualifiedClassName(), null); + ensureClass(model, fc.localName(), null); } } } @@ -81,20 +115,20 @@ protected void createClasses(JCodeModel model, List records) { /** * ensure a jdefinedclass exists for given name */ - protected JDefinedClass ensureClass(JCodeModel model, String fullyQualifiedName, FieldOptions options) { - JDefinedClass clazz = definedClasses.computeIfAbsent(fullyQualifiedName, n -> { + protected JDefinedClass ensureClass(JCodeModel model, String localName, FieldOptions options) { + JDefinedClass clazz = definedClasses.computeIfAbsent(localName, n -> { try { - return model._class(n); + return model._class(expandClassName(n)); } catch (JCodeModelException e) { throw new RuntimeException(e); } }); - String simpleName = fullyQualifiedName.replaceAll(".*\\.", ""); + String simpleName = localName.replaceAll(".*\\.", ""); simpleDefinedClasses.computeIfAbsent(simpleName, n -> new HashSet<>()).add(clazz); if (options == null) { - pathOptions.computeIfAbsent(fullyQualifiedName, cn -> new FieldOptions()); + pathOptions.computeIfAbsent(localName, cn -> new FieldOptions()); } else { - pathOptions.put(fullyQualifiedName, options); + pathOptions.put(localName, options); } return clazz; } @@ -104,14 +138,17 @@ protected JDefinedClass ensureClass(JCodeModel model, String fullyQualifiedName, */ protected void updateParentOptions(List records) { for (Entry e : pathOptions.entrySet()) { - e.getValue().setParent(findParentOption(e.getKey())); + if (!e.getKey().isBlank()) { + e.getValue().setParent(findParentOption(e.getKey())); + } } } /** - * find the fieldoptions associated to the longest leading path of the child. - * eg. if child is my.own.LittleClass, and there is a fieldoptions stored for my - * and one for my.own, then this would return the fieldoptions associated to + * find the FieldOptions associated to the longest leading path of the child. + * eg. if child is my.own.LittleClass, and there is a fieldoptions stored for + * "my" + * and one for "my.own", then this would return the fieldoptions associated to * my.own. */ protected FieldOptions findParentOption(String fullChildName) { @@ -123,6 +160,9 @@ protected FieldOptions findParentOption(String fullChildName) { search = idx > -1 ? search.substring(0, idx) : null; found = pathOptions.get(search); } while (found == null && search != null && !search.isBlank()); + if (found == null) { + found = pathOptions.get(""); + } return found; } @@ -132,18 +172,20 @@ protected FieldOptions findParentOption(String fullChildName) { protected void applyInheritance(JCodeModel model, List records) { for (FlatStructRecord rec : records) { if (rec instanceof ClassCreation cc) { - if (cc.parentClassName() != null && !cc.parentClassName().isBlank()) { - AbstractJType parentType = resolveType(model, cc.parentClassName()); + if (cc.parentType() != null + && cc.parentType().baseClassName() != null + && !cc.parentType().baseClassName().isBlank()) { + AbstractJType parentType = resolveConcreteType(model, cc.parentType()); if (parentType == null) { - throw new RuntimeException("can't resolve type " + cc.parentClassName() + " as parent of " - + cc.fullyQualifiedClassName()); + throw new RuntimeException("can't resolve type " + cc.parentType() + " as parent of " + + cc.localName()); } if (parentType instanceof JPrimitiveType jpt) { throw new RuntimeException( - "class " + cc.fullyQualifiedClassName() + " cannot extend the primitive class " + jpt); + "class " + cc.localName() + " cannot extend the primitive class " + jpt); } AbstractJClass parentJClass = (AbstractJClass) parentType; - JDefinedClass ownerClass = definedClasses.get(cc.fullyQualifiedClassName()); + JDefinedClass ownerClass = definedClasses.get(cc.localName()); if (parentJClass.isInterface()) { ownerClass._implements(parentJClass); } else { @@ -158,29 +200,54 @@ protected void applyInheritance(JCodeModel model, List records protected void createFields(JCodeModel model, List records) { for (FlatStructRecord rec : records) { if (rec instanceof SimpleField af) { - JDefinedClass owner = Objects.requireNonNull(definedClasses.get(af.fullyQualifiedClassName()), - "can't find defined class " + af.fullyQualifiedClassName() + " for field " + af); - FieldOptions ownerOptions = pathOptions.get(owner.fullName()); - Objects.requireNonNull(ownerOptions, "can't find options for class " + owner.fullName() + JDefinedClass owner = Objects.requireNonNull(definedClasses.get(af.localName()), + "can't find defined class " + af.localName() + " for field " + af); + FieldOptions ownerOptions = pathOptions.get(af.localName()); + Objects.requireNonNull(ownerOptions, "can't find options for class " + af.localName() + " known classes are " + pathOptions.keySet()); af.options().setParent(ownerOptions); - AbstractJType fieldType = resolveType(model, af.fieldInternalClassName(), af.arrayDepth()); + + AbstractJType fieldType = resolveType(model, af.fieldType()); if (fieldType == null) { throw new RuntimeException("can't resolve type " + af.fieldClassName() + " for field " - + af.fullyQualifiedClassName() + "::" + af.fieldName()); - } - if (af.options().isList()) { - if (fieldType instanceof JPrimitiveType) { - throw new RuntimeException("can't create a list of primitive : " + fieldType + " for field " - + af.fullyQualifiedClassName() + "::" + af.fieldName()); - } - fieldType = model.ref(List.class).narrow(fieldType); + + af.localName() + "::" + af.fieldName()); } addField(owner, fieldType, af.fieldName(), af.options(), model); } } } + protected AbstractJType resolveType(JCodeModel model, Encapsulated enc) { + AbstractJType ret = resolveType(model, enc.baseClassName()); + for (Encapsulation e : enc.encapsulations()) { + ret = e.apply(ret, model); + } + return ret; + } + + protected AbstractJType resolveConcreteType(JCodeModel model, Encapsulated enc) { + AbstractJType ret = resolveType(model, enc.baseClassName()); + for (Encapsulation e : enc.encapsulations()) { + ret = e.applyConcrete(ret, model, concrete); + } + return ret; + } + + /** + * resolve a name to a class. The order of searching is : + *
    + *
  1. a created class with that exact local name
  2. + *
  3. a created class with that exact simple name. If several classes exist + * with that simple name, throws an exception
  4. + *
  5. a static class with that exact full name
  6. + *
  7. a static class with that exact full name in package java.lang
  8. + *
  9. a static class with that exact full name in package java.util
  10. + *
+ * + * @param model + * @param typeName + * @return + */ protected AbstractJType resolveType(JCodeModel model, String typeName) { AbstractJType defined = definedClasses.get(typeName); if (defined == null) { @@ -197,30 +264,38 @@ protected AbstractJType resolveType(JCodeModel model, String typeName) { if (defined != null) { return defined; } - try { - Class staticResolved = convertStaticType(typeName); + Class staticResolved = staticAlias(typeName); + for (String prefix : new String[] { null, "java.lang", "java.util" }) { if (staticResolved != null) { - return model._ref(staticResolved); + break; + } + try { + staticResolved = Class.forName((prefix == null || prefix.isBlank() ? "" : prefix + ".") + typeName); + } catch (ClassNotFoundException e) { } - } catch (ClassNotFoundException e) { } - return null; + return staticResolved == null ? null : model._ref(staticResolved); } - protected AbstractJType resolveType(JCodeModel model, String typeName, int arrayLevel) { + protected AbstractJType resolveType(JCodeModel model, String typeName, List encapsulations) { AbstractJType ret = resolveType(model, typeName); if (ret == null) { return null; } - for (int i = 0; i < arrayLevel; i++) { - ret = ret.array(); + for (Encapsulation e : encapsulations) { + ret = e.apply(ret, model); } return ret; } - protected Class convertStaticType(String typeName) throws ClassNotFoundException { - return switch (typeName) { + /** + * convert an alias to a static class + * + * @return corresponding static class, or null if alias does not match any + */ + protected Class staticAlias(String alias) { + return switch (alias) { case "bool", "boolean" -> boolean.class; case "Bool", "Boolean" -> Boolean.class; case "char", "character" -> char.class; @@ -234,53 +309,69 @@ protected Class convertStaticType(String typeName) throws ClassNotFoundExcept case "date", "instant", "datetime" -> Instant.class; case "long" -> long.class; case "Long" -> Long.class; + case "obj", "object" -> Object.class; case "string", "String" -> String.class; - default -> Class.forName(typeName); + default -> null; }; } protected void addField(JDefinedClass jdc, AbstractJType type, String fieldName, FieldOptions options, JCodeModel model) { - JFieldVar fv = jdc.field(options.getVisibility().jmod | (options.isFinal() ? JMod.FINAL : 0), type, fieldName); + FieldCanner fc = getCanner(options.getCanner()); + int fieldMods = options.getVisibility().jmod | (options.isFinal() ? JMod.FINAL : 0); + JFieldVar fv = fc == null + ? jdc.field(fieldMods, type, fieldName) + : fc.makeType(jdc, fieldName, type, fieldMods); if (options.isSetter() && !options.isFinal()) { - addSetter(fv, jdc, model, options); + addSetter(fv, jdc, model, options, type, fc); } if (options.isGetter()) { - addGetter(fv, jdc); + addGetter(fv, jdc, type, fc); + } + if (fc != null) { + fc.addAdditional(fv, options); } } - protected void addGetter(JFieldVar fv, JDefinedClass jdc) { - AbstractJType retType = fv.type(); + protected void addGetter(JFieldVar fv, JDefinedClass jdc, AbstractJType retType, FieldCanner fc) { + IJExpression retExpression = fc == null ? fv : fc.makeGetter(fv); + if (retExpression == null) { + return ; + } String methName = "get" + Character.toUpperCase(fv.name().charAt(0)) + (fv.name().length() < 2 ? "" : fv.name().substring(1)); JMethod meth = jdc.method(JMod.PUBLIC, retType, methName); - meth.body()._return(fv); + meth.body()._return(retExpression); meth.javadoc().add("@return the {@link #" + fv.name() + "}"); } - protected void addSetter(JFieldVar fv, JDefinedClass jdc, JCodeModel model, FieldOptions options) { - AbstractJType paramType = fv.type(); + protected void addSetter(JFieldVar fv, JDefinedClass jdc, JCodeModel model, FieldOptions options, + AbstractJType paramType, FieldCanner fc) { String methName = "set" + Character.toUpperCase(fv.name().charAt(0)) + (fv.name().length() < 2 ? "" : fv.name().substring(1)); JMethod meth = jdc.method(JMod.PUBLIC, model.VOID, methName); JVar param = meth.param(paramType, fv.name()); - meth.body().assign(JExpr.refthis(fv), param); + IJStatement assignExpression = fc == null ? JExpr.assign(JExpr.refthis(fv), param) : fc.makeSetter(param, fv); + if (assignExpression == null) { + jdc.methods().remove(meth); + return; + } + meth.body().add(assignExpression); if (options.isLastUpdated()) { JFieldVar lastUpdated = classLastUpdated.computeIfAbsent(jdc.fullName(), - n -> addLastUpdated(jdc, model)); + n -> addLastUpdated(jdc, model, options)); meth.body().assign(JExpr.refthis(lastUpdated), model.ref(Instant.class).staticInvoke("now")); } meth.javadoc().add("set the {@link #" + fv.name() + "}"); } - protected JFieldVar addLastUpdated(JDefinedClass jdc, JCodeModel model) { - FieldOptions ownerOptions = pathOptions.get(jdc.fullName()); + protected JFieldVar addLastUpdated(JDefinedClass jdc, JCodeModel model, FieldOptions fieldOptions) { + FieldOptions ownerOptions = fieldOptions.getParent(); JFieldVar lastUpdated = jdc.field(ownerOptions.getVisibility().jmod, model.ref(Instant.class), "lastUpdated", JExpr._null()); lastUpdated.javadoc().add("last time the class was directly set a field using a setter"); if (ownerOptions.isGetter()) { - addGetter(lastUpdated, jdc); + addGetter(lastUpdated, jdc, lastUpdated.type(), null); } return lastUpdated; } @@ -307,6 +398,10 @@ protected void createConstructors(JCodeModel model, JDefinedClass createdClass, } AbstractJClass parent; if ((parent = createdClass._extends()) != null) { + if (parent instanceof JNarrowedClass narrowed) { + parent = narrowed.basis(); + } +// TODO convert to pattern matching post java 21 if (parent instanceof JDefinedClass parentClass) { createConstructors(model, createdClass, parentClass, done); } else if (parent instanceof JReferencedClass parentClass) { @@ -432,12 +527,14 @@ protected void applyRedirects(JCodeModel model, List records) for (FlatStructRecord rec : records) { if (rec instanceof SimpleField af) { if (af.options().isRedirect()) { - if (af.arrayDepth() > 0) { + // can't redirect calls to a field encapsulated, eg String[] or List + + if (af.fieldType().encapsulations().size() > 0) { continue; } - JDefinedClass fieldOwner = Objects.requireNonNull(definedClasses.get(af.fullyQualifiedClassName()), - "can't find defined class " + af.fullyQualifiedClassName() + " for field " + af); - AbstractJType fieldType = resolveType(model, af.fieldInternalClassName()); + JDefinedClass fieldOwner = Objects.requireNonNull(definedClasses.get(af.localName()), + "can't find defined class " + af.localName() + " for field " + af); + AbstractJType fieldType = resolveType(model, af.fieldType().baseClassName()); if (fieldType instanceof JDefinedClass jdc) { applyRedirect(model, af, fieldOwner, jdc); } else if (fieldType instanceof JReferencedClass jrc) { @@ -454,7 +551,6 @@ protected void applyRedirects(JCodeModel model, List records) protected void applyRedirect(JCodeModel model, SimpleField af, JDefinedClass fieldOwner, JDefinedClass fieldType) { for (JMethod m : fieldType.methods()) { - if (m.mods().isPublic() && !m.mods().isStatic()) { int mods = redirectMethodMods(m.mods().getValue()); JMethod newMeth = fieldOwner.method(mods, m.type(), m.name()); @@ -482,7 +578,13 @@ protected void applyRedirect(JCodeModel model, SimpleField af, JDefinedClass fie if (fieldClass.isPrimitive()) { return; } - for (Method m : fieldClass.getMethods()) { + Method[] sortedMethods = fieldClass.getMethods(); + Arrays.sort(sortedMethods, Comparator + .comparing(Method::getName) + .thenComparing(Method::getParameterCount) + // Method::toString actually short signature + .thenComparing(Comparator.comparing(Method::toString))); + for (Method m : sortedMethods) { if ( // synthetic methods are added by the compiler, not in the actual code m.isSynthetic() @@ -516,4 +618,83 @@ static int redirectMethodMods(int jmods) { & ~JMod.STRICTFP; } + protected void applyToFieldOptions(String optStr, FieldOptions options) { + if (optStr == null || optStr.isBlank()) { + return; + } else { + optStr = optStr.trim(); + } + FieldVisibility fv = FieldVisibility.of(optStr); + if (fv != null) { + fv.apply(options); + return; + } + FieldOption fa = FieldOption.of(optStr); + if (fa != null) { + fa.apply(options); + return; + } + if (cannersAliases().contains(optStr)) { + options.setCanner(optStr); + return; + } + throw new UnsupportedOperationException("can't deduce option from " + optStr); + + } + + // canners handling + + /** + * stream the known canners fieldgenerator by their name, to buld the internal + * map.
+ * The usual overriding concatenates the super one with its own, so that its own + * overwrites the super's. + * + * @return stream of canner name to canner generator. The names are the one used + * to parse and apply the fields' canner system + */ + Stream>> streamCanners() { + return Stream.of( + new SimpleEntry<>("weakref", WeakReferenceCanner.class), + new SimpleEntry<>("", NoCanner.class)); + } + + private Map canners = null; + + /** + * @return map of canner alias to canner implementation + */ + protected Map canners() { + if (canners == null) { + canners = streamCanners() + .sequential() // to avoid merging inconsistency + .collect( + Collectors.toMap(Entry::getKey, + e -> { + try { + return e.getValue().getConstructor().newInstance(); + } catch (InstantiationException | IllegalAccessException + | IllegalArgumentException + | InvocationTargetException | NoSuchMethodException + | SecurityException e1) { + throw new RuntimeException(e1); + } + }, + (o1, o2) -> o2)// merging using the last one + ); + } + return canners; + } + + public FieldCanner getCanner(String alias) { + if (alias == null) { + alias = ""; + } + return canners().get(alias); + } + + public Set cannersAliases() { + return canners().keySet(); + } + } diff --git a/plugin/plugin/src/main/java/com/helger/jcodemodel/plugin/maven/generators/flatstruct/ConcreteTypes.java b/plugin/plugin/src/main/java/com/helger/jcodemodel/plugin/maven/generators/flatstruct/ConcreteTypes.java new file mode 100644 index 00000000..1032e9d3 --- /dev/null +++ b/plugin/plugin/src/main/java/com/helger/jcodemodel/plugin/maven/generators/flatstruct/ConcreteTypes.java @@ -0,0 +1,47 @@ +package com.helger.jcodemodel.plugin.maven.generators.flatstruct; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; + +public class ConcreteTypes { + + public static final String CONCRETE_LIST_PARAM = "concrete.list"; + public static final String CONCRETE_MAP_PARAM = "concrete.map"; + public static final String CONCRETE_SET_PARAM = "concrete.set"; + + public Class list, map, set; + + public static ConcreteTypes from(Map params) { + ConcreteTypes ret = new ConcreteTypes(); + ret.list = findClass(params.get(CONCRETE_LIST_PARAM), ArrayList.class); + ret.map = findClass(params.get(CONCRETE_MAP_PARAM), HashMap.class); + ret.set = findClass(params.get(CONCRETE_SET_PARAM), HashSet.class); + return ret; + } + + public static Class findClass(String name, Class defaultClass) { + if (name == null) { + return defaultClass; + } + Class ret = null; + try { + ret = Class.forName(name); + } catch (ClassNotFoundException e) { + } + if (ret != null) { + return ret; + } + for (String prefix : new String[] { "java.util", "java.lang" }) { + try { + ret = Class.forName(prefix + "." + name); + if (ret != null) { + return ret; + } + } catch (ClassNotFoundException e) { + } + } + throw new RuntimeException("can't find class " + name); + } +} \ No newline at end of file diff --git a/plugin/plugin/src/main/java/com/helger/jcodemodel/plugin/maven/generators/flatstruct/FieldCanner.java b/plugin/plugin/src/main/java/com/helger/jcodemodel/plugin/maven/generators/flatstruct/FieldCanner.java new file mode 100644 index 00000000..deb5df7b --- /dev/null +++ b/plugin/plugin/src/main/java/com/helger/jcodemodel/plugin/maven/generators/flatstruct/FieldCanner.java @@ -0,0 +1,71 @@ +package com.helger.jcodemodel.plugin.maven.generators.flatstruct; + +import com.helger.jcodemodel.AbstractJType; +import com.helger.jcodemodel.IJExpression; +import com.helger.jcodemodel.IJStatement; +import com.helger.jcodemodel.JCodeModel; +import com.helger.jcodemodel.JDefinedClass; +import com.helger.jcodemodel.JFieldVar; +import com.helger.jcodemodel.JVar; + +/** + * interface to make a field containered (canned). + */ +public interface FieldCanner { + + AbstractJType makeType(JCodeModel model, AbstractJType type); + + /** + * create a field in the class, as the actual container. Can be overriden eg to + * add init call + * + * @param model + * @param jdc + * @param fieldName + * @param type + * @param jmods + * @return + */ + default JFieldVar makeType(JDefinedClass jdc, String fieldName, AbstractJType type, int jmods) { + return jdc.field( + jmods, + makeType(jdc.owner(), type), + fieldName); + } + + /** + * create the assignemnt to the field for the setter.
+ * Typically, fv=param with no canner, or fv.[canSetter](param), or even fv=new + * [canimplementation](param) .
+ * returning null prevents the default setter method + */ + IJStatement makeSetter(JVar param, JFieldVar fv); + + /** + * create the way to return the actual value in the container.
+ * typically, (field) with no canner, or field.canGetter() .
+ * returning null prevents the default getter method + */ + IJExpression makeGetter(JFieldVar fv); + + /** + * for dev to instantiate + */ + default void addAdditional(JFieldVar field, FieldOptions options) { + if (options.isGetter()) { + addAdditionalGetter(field, options); + } + if (options.isSetter() && !options.isFinal()) { + addAdditionalSetter(field, options); + } + } + + default void addAdditionalGetter(JFieldVar field, FieldOptions options) { + + } + + default void addAdditionalSetter(JFieldVar field, FieldOptions options) { + + } + +} diff --git a/plugin/plugin/src/main/java/com/helger/jcodemodel/plugin/maven/generators/flatstruct/FieldConstruct.java b/plugin/plugin/src/main/java/com/helger/jcodemodel/plugin/maven/generators/flatstruct/FieldOption.java similarity index 84% rename from plugin/plugin/src/main/java/com/helger/jcodemodel/plugin/maven/generators/flatstruct/FieldConstruct.java rename to plugin/plugin/src/main/java/com/helger/jcodemodel/plugin/maven/generators/flatstruct/FieldOption.java index 2cab2e9d..2645da06 100644 --- a/plugin/plugin/src/main/java/com/helger/jcodemodel/plugin/maven/generators/flatstruct/FieldConstruct.java +++ b/plugin/plugin/src/main/java/com/helger/jcodemodel/plugin/maven/generators/flatstruct/FieldOption.java @@ -3,7 +3,7 @@ /** * Additional features to add when constructing fields */ -public enum FieldConstruct { +public enum FieldOption { GETTER { @Override @@ -67,23 +67,11 @@ public void apply(FieldOptions opt) { public void apply(FieldOptions opt) { opt.setFinal(false); } - }, - LIST { - @Override - public void apply(FieldOptions opt) { - opt.setList(true); - } - }, - NOLIST { - @Override - public void apply(FieldOptions opt) { - opt.setList(false); - } },; public abstract void apply(FieldOptions opt); - public static FieldConstruct of(String value) { + public static FieldOption of(String value) { if (value == null || value.isBlank()) { return null; } @@ -98,8 +86,6 @@ public static FieldConstruct of(String value) { case "noredirect" -> NOREDIRECT; case "final", "const", "immutable" -> FINAL; case "nofinal", "noconst", "mutable" -> NOFINAL; - case "list" -> LIST; - case "nolist" -> NOLIST; default -> null; }; } diff --git a/plugin/plugin/src/main/java/com/helger/jcodemodel/plugin/maven/generators/flatstruct/FieldOptions.java b/plugin/plugin/src/main/java/com/helger/jcodemodel/plugin/maven/generators/flatstruct/FieldOptions.java index 3b20ebea..b7ab8eb3 100644 --- a/plugin/plugin/src/main/java/com/helger/jcodemodel/plugin/maven/generators/flatstruct/FieldOptions.java +++ b/plugin/plugin/src/main/java/com/helger/jcodemodel/plugin/maven/generators/flatstruct/FieldOptions.java @@ -13,6 +13,31 @@ public FieldOptions setParent(FieldOptions parent) { return this; } + public FieldOptions getParent() { + return parent; + } + + // canner system, by alias + + private String canner = null; + + public FieldOptions setCanner(String canner) { + this.canner = canner; + return this; + } + + public static final String DEFAULT_CANNER = null; + + public String getCanner() { + if (canner != null) { + return canner; + } + if (parent != null) { + return parent.getCanner(); + } + return DEFAULT_CANNER; + } + // is field final private Boolean _final = null; @@ -77,27 +102,6 @@ public boolean isLastUpdated() { return DEFAULT_LAST_UPDATED; } - // is field a list - - private Boolean list = null; - - public FieldOptions setList(Boolean list) { - this.list = list; - return this; - } - - public static final boolean DEFAULT_LIST = false; - - public boolean isList() { - if (list != null) { - return list; - } - if (parent != null) { - return parent.isList(); - } - return DEFAULT_LIST; - } - // redirect field methods on the owner class private Boolean redirect = null; @@ -161,4 +165,5 @@ public FieldVisibility getVisibility() { return DEFAULT_VISIBILITY; } + } diff --git a/plugin/plugin/src/main/java/com/helger/jcodemodel/plugin/maven/generators/flatstruct/FlatStructRecord.java b/plugin/plugin/src/main/java/com/helger/jcodemodel/plugin/maven/generators/flatstruct/FlatStructRecord.java index b9d21a83..dec53efb 100644 --- a/plugin/plugin/src/main/java/com/helger/jcodemodel/plugin/maven/generators/flatstruct/FlatStructRecord.java +++ b/plugin/plugin/src/main/java/com/helger/jcodemodel/plugin/maven/generators/flatstruct/FlatStructRecord.java @@ -1,19 +1,29 @@ package com.helger.jcodemodel.plugin.maven.generators.flatstruct; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import com.helger.jcodemodel.AbstractJType; +import com.helger.jcodemodel.JCodeModel; + public sealed interface FlatStructRecord { - String fullyQualifiedClassName(); + String localName(); /** * specify package-wide options */ - public record PackageCreation(String fullyQualifiedClassName, FieldOptions options) implements FlatStructRecord { + public record PackageCreation(String localName, FieldOptions options) implements FlatStructRecord { } /** * create a class, with options */ - public record ClassCreation(String fullyQualifiedClassName, String parentClassName, FieldOptions options) + public record ClassCreation(String localName, Encapsulated parentType, FieldOptions options) implements FlatStructRecord { } @@ -34,14 +44,142 @@ public sealed interface FieldCreation extends FlatStructRecord { } /** A field definition in a class, with a simple type that can be an array */ - public record SimpleField(String fullyQualifiedClassName, String fieldName, String fieldInternalClassName, - int arrayDepth, FieldOptions options) + public record SimpleField(String localName, String fieldName, Encapsulated fieldType, + FieldOptions options) implements FieldCreation { @Override public String fieldClassName() { - return fieldInternalClassName + "[]".repeat(arrayDepth); + return fieldType().toString(); + } + } + + enum Encapsulation { + ARRAY() { + @Override + public String apply(String encapsulatedClassName) { + return encapsulatedClassName + " []"; + } + + @Override + public AbstractJType apply(AbstractJType t, JCodeModel cm) { + return t.array(); + } + + @Override + public AbstractJType applyConcrete(AbstractJType t, JCodeModel cm, ConcreteTypes concrete) { + return t.array(); + } + }, + LIST() { + @Override + public String apply(String encapsulatedClassName) { + return "List<" + encapsulatedClassName + ">"; + } + + @Override + public AbstractJType apply(AbstractJType e, JCodeModel cm) { + return cm.ref(List.class).narrow(e); + } + + @Override + public AbstractJType applyConcrete(AbstractJType e, JCodeModel cm, ConcreteTypes concrete) { + return cm.ref(concrete.list).narrow(e); + } + }, + MAP() { + @Override + public String apply(String encapsulatedClassName) { + return "Map"; + } + + @Override + public AbstractJType apply(AbstractJType e, JCodeModel cm) { + return cm.ref(Map.class).narrow(cm.ref(Object.class)).narrow(e); + } + + @Override + public AbstractJType applyConcrete(AbstractJType e, JCodeModel cm, ConcreteTypes concrete) { + return cm.ref(concrete.map).narrow(cm.ref(Object.class)).narrow(e); + } + }, + SET() { + @Override + public String apply(String encapsulatedClassName) { + return "Set<" + encapsulatedClassName + ">"; + } + + @Override + public AbstractJType apply(AbstractJType e, JCodeModel cm) { + return cm.ref(Set.class).narrow(e); + } + + @Override + public AbstractJType applyConcrete(AbstractJType e, JCodeModel cm, ConcreteTypes concrete) { + return cm.ref(concrete.set).narrow(e); + } + }; + + public abstract String apply(String encapsulatedClassName); + + public abstract AbstractJType apply(AbstractJType e, JCodeModel cm); + + public abstract AbstractJType applyConcrete(AbstractJType e, JCodeModel cm, ConcreteTypes concrete); + + public static Encapsulation parse(String s) { + if (s == null) { + return null; + } + // remove internal whitespaces for eg arrays + s = s.toLowerCase().replaceAll("\\s", ""); + return switch (s) { + case "[]" -> ARRAY; + case "list" -> LIST; + case "map" -> MAP; + case "set" -> SET; + default -> { + throw new UnsupportedOperationException(); + } + }; } } + record Encapsulated(String baseClassName, List encapsulations) { + + private static final Pattern BASECLASS_PAT = Pattern.compile("\\s*([\\w\\.]+)\\s*(.*)"); + + private static final Pattern ENCAPS_PAT = Pattern.compile("\\s*(\\[\\s*\\]|[\\w]+)\\s*(.*)"); + + public static Encapsulated parse(String s) { + String baseClass = null; + ArrayList encapsulations = new ArrayList<>(); + if (s == null) { + return new Encapsulated(baseClass, encapsulations); + } + Matcher m = BASECLASS_PAT.matcher(s); + if (m.matches()) { + baseClass = m.group(1); + String restType = m.group(2); + while (restType != null && !restType.isBlank()) { + Matcher m2 = ENCAPS_PAT.matcher(restType); + if (!m2.matches()) { + break; + } + encapsulations.add(Encapsulation.parse(m2.group(1))); + restType = m2.group(2); + } + } + return new Encapsulated(baseClass, encapsulations); + } + + @Override + public String toString() { + String ret = baseClassName(); + for (Encapsulation enc : encapsulations()) { + ret = enc.apply(ret); + } + return ret; + } + + } } diff --git a/plugin/plugin/src/main/java/com/helger/jcodemodel/plugin/maven/generators/flatstruct/canners/ARefCanner.java b/plugin/plugin/src/main/java/com/helger/jcodemodel/plugin/maven/generators/flatstruct/canners/ARefCanner.java new file mode 100644 index 00000000..e4c0af9f --- /dev/null +++ b/plugin/plugin/src/main/java/com/helger/jcodemodel/plugin/maven/generators/flatstruct/canners/ARefCanner.java @@ -0,0 +1,36 @@ +package com.helger.jcodemodel.plugin.maven.generators.flatstruct.canners; + +import com.helger.jcodemodel.AbstractJType; +import com.helger.jcodemodel.IJExpression; +import com.helger.jcodemodel.IJStatement; +import com.helger.jcodemodel.JCodeModel; +import com.helger.jcodemodel.JExpr; +import com.helger.jcodemodel.JFieldVar; +import com.helger.jcodemodel.JVar; +import com.helger.jcodemodel.plugin.maven.generators.flatstruct.FieldCanner; + +public abstract class ARefCanner implements FieldCanner { + + public final Class refClass; + + public ARefCanner(Class refClass) { + this.refClass = refClass; + } + + @Override + public AbstractJType makeType(JCodeModel model, AbstractJType type) { + return model.ref(refClass).narrow(type); + } + + @Override + public IJExpression makeGetter(JFieldVar fv) { + return fv.invoke("get"); + } + + @Override + public IJStatement makeSetter(JVar param, JFieldVar fv) { + return JExpr.refthis(fv).assign(fv.type()._new().arg(param)); + } + + +} diff --git a/plugin/plugin/src/main/java/com/helger/jcodemodel/plugin/maven/generators/flatstruct/canners/NoCanner.java b/plugin/plugin/src/main/java/com/helger/jcodemodel/plugin/maven/generators/flatstruct/canners/NoCanner.java new file mode 100644 index 00000000..26abc1ce --- /dev/null +++ b/plugin/plugin/src/main/java/com/helger/jcodemodel/plugin/maven/generators/flatstruct/canners/NoCanner.java @@ -0,0 +1,30 @@ +package com.helger.jcodemodel.plugin.maven.generators.flatstruct.canners; + +import com.helger.jcodemodel.AbstractJType; +import com.helger.jcodemodel.IJExpression; +import com.helger.jcodemodel.IJStatement; +import com.helger.jcodemodel.JCodeModel; +import com.helger.jcodemodel.JExpr; +import com.helger.jcodemodel.JFieldVar; +import com.helger.jcodemodel.JVar; +import com.helger.jcodemodel.plugin.maven.generators.flatstruct.FieldCanner; + +public class NoCanner implements FieldCanner { + + @Override + public AbstractJType makeType(JCodeModel model, AbstractJType type) { + return type; + } + + @Override + public IJStatement makeSetter(JVar param, JFieldVar fv) { + return JExpr.assign(JExpr.refthis(fv), param); + } + + @Override + public IJExpression makeGetter(JFieldVar fv) { + return fv; + } + + public static final NoCanner INSTANCE = new NoCanner(); +} diff --git a/plugin/plugin/src/main/java/com/helger/jcodemodel/plugin/maven/generators/flatstruct/canners/reference/WeakReferenceCanner.java b/plugin/plugin/src/main/java/com/helger/jcodemodel/plugin/maven/generators/flatstruct/canners/reference/WeakReferenceCanner.java new file mode 100644 index 00000000..399ae9d4 --- /dev/null +++ b/plugin/plugin/src/main/java/com/helger/jcodemodel/plugin/maven/generators/flatstruct/canners/reference/WeakReferenceCanner.java @@ -0,0 +1,13 @@ +package com.helger.jcodemodel.plugin.maven.generators.flatstruct.canners.reference; + +import java.lang.ref.WeakReference; + +import com.helger.jcodemodel.plugin.maven.generators.flatstruct.canners.ARefCanner; + +public class WeakReferenceCanner extends ARefCanner { + + public WeakReferenceCanner() { + super(WeakReference.class); + } + +} diff --git a/plugin/plugin/src/test/java/com/helger/jcodemodel/plugin/maven/generators/flatstruct/FlatStructRecordTest.java b/plugin/plugin/src/test/java/com/helger/jcodemodel/plugin/maven/generators/flatstruct/FlatStructRecordTest.java new file mode 100644 index 00000000..f51440b6 --- /dev/null +++ b/plugin/plugin/src/test/java/com/helger/jcodemodel/plugin/maven/generators/flatstruct/FlatStructRecordTest.java @@ -0,0 +1,34 @@ +package com.helger.jcodemodel.plugin.maven.generators.flatstruct; + +import org.junit.Assert; +import org.junit.Test; + +import com.helger.jcodemodel.plugin.maven.generators.flatstruct.FlatStructRecord.Encapsulated; +import com.helger.jcodemodel.plugin.maven.generators.flatstruct.FlatStructRecord.Encapsulation; + +public class FlatStructRecordTest { + + @Test + public void testParse() { + Encapsulated test1 = Encapsulated.parse("String[]"); + Assert.assertEquals("String", test1.baseClassName()); + Assert.assertEquals(Encapsulation.ARRAY, test1.encapsulations().get(0)); + + Encapsulated test2 = Encapsulated.parse("int [ ][ ] map"); + Assert.assertEquals("int", test2.baseClassName()); + Assert.assertEquals(Encapsulation.ARRAY, test2.encapsulations().get(0)); + Assert.assertEquals(Encapsulation.ARRAY, test2.encapsulations().get(1)); + Assert.assertEquals(Encapsulation.MAP, test2.encapsulations().get(2)); + + Encapsulated test3 = Encapsulated.parse("double []set[]"); + Assert.assertEquals("double", test3.baseClassName()); + Assert.assertEquals(Encapsulation.ARRAY, test3.encapsulations().get(0)); + Assert.assertEquals(Encapsulation.SET, test3.encapsulations().get(1)); + Assert.assertEquals(Encapsulation.ARRAY, test3.encapsulations().get(2)); + + Encapsulated test4 = Encapsulated.parse("java.lang.String MAP "); + Assert.assertEquals("java.lang.String", test4.baseClassName()); + Assert.assertEquals(Encapsulation.MAP, test4.encapsulations().get(0)); + } + +} diff --git a/sh/debugCSV b/sh/debugCSV new file mode 100755 index 00000000..4c79ee8b --- /dev/null +++ b/sh/debugCSV @@ -0,0 +1,5 @@ +#!/bin/bash + +# install only the csv plugin example alongside its dependencies, with debuging on + +reset ; mvn clean install -pl com.helger.jcodemodel.examples.plugin:csv -am -e \ No newline at end of file diff --git a/sh/debugJSON b/sh/debugJSON new file mode 100755 index 00000000..8a1ebacf --- /dev/null +++ b/sh/debugJSON @@ -0,0 +1,5 @@ +#!/bin/bash + +# install only the json plugin example alongside its dependencies, with debuging on + +reset ; mvn clean install -pl com.helger.jcodemodel.examples.plugin:json -am -e \ No newline at end of file