diff --git a/README.md b/README.md index 137132a1..c0283c87 100644 --- a/README.md +++ b/README.md @@ -3,23 +3,52 @@ A fork of the com.sun.codemodel 2.7-SNAPSHOT. The classes in this project use a different package name `com.helger.jcodemodel` to avoid conflicts with other `com.sun.codemodel` instances that might be floating around in the classpath. -That of course implies, that this artefact cannot directly be used with JAXB, since the configuration of +That of course implies, that this artifact cannot directly be used with JAXB, since the configuration of this would be very tricky. A site with the links to the [API docs](http://phax.github.io/jcodemodel/) etc. is available. -## Maven usage +## Import in Maven + +### Straightforward import Add the following to your pom.xml to use this artifact (where `x.y.z` denotes the version): ```xml - - com.helger - jcodemodel - x.y.z - + + + + com.helger + jcodemodel + x.y.z + ``` +### Bill Of Materials import + +In case you want to use several of our projects, you may import the bom first, then the required modules : + +```xml + + + + + com.helger.jcodemodel + bom + x.y.z + pom + import + +... + + + com.helger + jcodemodel + +``` + +In that case, the bom import defines the version of the other projects. + # News and noteworthy v4.2.0 - work in progress diff --git a/bom/pom.xml b/bom/pom.xml new file mode 100644 index 00000000..abf74be2 --- /dev/null +++ b/bom/pom.xml @@ -0,0 +1,49 @@ + + 4.0.0 + + com.helger.jcodemodel + jcodemodel-parent-pom + 4.2.0-SNAPSHOT + + bom + POM JCM BOM + pom + + + + + + com.helger + jcodemodel + ${project.version} + + + com.helger.jcodemodel.plugin.generators + csv + ${project.version} + + + com.helger.jcodemodel.plugin.generators + json + ${project.version} + + + com.helger.jcodemodel.plugin.generators + yaml + ${project.version} + + + + + + + + + com.helger.jcodemodel + jcodemodel-maven-plugin + ${project.version} + + + + + \ No newline at end of file diff --git a/examples/pom.xml b/examples/pom.xml index b7958ac4..b34d10a2 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -19,8 +19,9 @@ 4.0.0 com.helger.jcodemodel - jcodemodel-parent-pom + bom 4.2.0-SNAPSHOT + ../bom examples pom diff --git a/jcodemodel/pom.xml b/jcodemodel/pom.xml index 1b11c7de..2353e3f7 100644 --- a/jcodemodel/pom.xml +++ b/jcodemodel/pom.xml @@ -44,8 +44,9 @@ 4.0.0 com.helger.jcodemodel - jcodemodel-parent-pom + bom 4.2.0-SNAPSHOT + ../bom com.helger jcodemodel diff --git a/jcodemodel/src/test/java/com/helger/jcodemodel/JRecordTest.java b/jcodemodel/src/test/java/com/helger/jcodemodel/JRecordTest.java index 1c03070e..1908d69c 100644 --- a/jcodemodel/src/test/java/com/helger/jcodemodel/JRecordTest.java +++ b/jcodemodel/src/test/java/com/helger/jcodemodel/JRecordTest.java @@ -40,12 +40,9 @@ */ package com.helger.jcodemodel; -import static org.junit.Assert.assertTrue; - import org.junit.Test; import com.helger.jcodemodel.exceptions.JCodeModelException; -import com.helger.jcodemodel.util.CodeModelTestsHelper; /** * Test class for Java record support. Java records (JEP 395, Java 16+) are a special kind of class @@ -55,467 +52,6 @@ */ public final class JRecordTest { - /** - * Test: Basic record with two components Expected output: - * - *
-   * package org.example;
-   *
-   * public record Point (int x, int y)
-   * {}
-   * 
- * - * @throws JCodeModelException - * In case of error - */ - @Test - public void testBasicRecord () throws JCodeModelException - { - final JCodeModel cm = new JCodeModel (); - final JDefinedClass rec = cm._package ("org.example")._record ("Point"); - rec.recordComponent (cm.INT, "x"); - rec.recordComponent (cm.INT, "y"); - - final String output = CodeModelTestsHelper.declare (rec); - assertTrue (output.contains ("record Point(int x, int y)")); - - CodeModelTestsHelper.parseCodeModel (cm); - } - - /** - * Test: Empty record (no components) Expected output: - * - *
-   * public record Empty ()
-   * {}
-   * 
- * - * @throws JCodeModelException - * In case of error - */ - @Test - public void testEmptyRecord () throws JCodeModelException - { - final JCodeModel cm = new JCodeModel (); - final JDefinedClass rec = cm._package ("org.example")._record ("Empty"); - - final String output = CodeModelTestsHelper.declare (rec); - assertTrue (output.contains ("record Empty()")); - - CodeModelTestsHelper.parseCodeModel (cm); - } - - /** - * Test: Record with object type components Expected output: - * - *
-   * public record Person (String name, Integer age)
-   * {}
-   * 
- * - * @throws JCodeModelException - * In case of error - */ - @Test - public void testRecordWithObjectComponents () throws JCodeModelException - { - final JCodeModel cm = new JCodeModel (); - final JDefinedClass rec = cm._package ("org.example")._record ("Person"); - rec.recordComponent (cm.ref (String.class), "name"); - rec.recordComponent (cm.ref (Integer.class), "age"); - - final String output = CodeModelTestsHelper.declare (rec); - assertTrue (output.contains ("record Person(java.lang.String name, java.lang.Integer age)")); - - CodeModelTestsHelper.parseCodeModel (cm); - } - - /** - * Test: Record implementing an interface Expected output: - * - *
-   * public record NamedPoint (int x, int y, String name) implements Comparable <NamedPoint>
-   * {}
-   * 
- * - * @throws JCodeModelException - * In case of error - */ - @Test - public void testRecordImplementsInterface () throws JCodeModelException - { - final JCodeModel cm = new JCodeModel (); - final JDefinedClass rec = cm._package ("org.example")._record ("NamedPoint"); - rec.recordComponent (cm.INT, "x"); - rec.recordComponent (cm.INT, "y"); - rec.recordComponent (cm.ref (String.class), "name"); - rec._implements (cm.ref (Comparable.class).narrow (rec)); - - final String output = CodeModelTestsHelper.declare (rec); - assertTrue (output, output.contains ("record NamedPoint(int x, int y, java.lang.String name)")); - assertTrue (output.contains ("implements java.lang.Comparable")); - - CodeModelTestsHelper.parseCodeModel (cm); - } - - /** - * Test: Generic record with type parameters Expected output: - * - *
-   * public record Pair <T, U> (T first, U second)
-   * {}
-   * 
- * - * @throws JCodeModelException - * In case of error - */ - @Test - public void testGenericRecord () throws JCodeModelException - { - final JCodeModel cm = new JCodeModel (); - final JDefinedClass rec = cm._package ("org.example")._record ("Pair"); - final JTypeVar t = rec.generify ("T"); - final JTypeVar u = rec.generify ("U"); - rec.recordComponent (t, "first"); - rec.recordComponent (u, "second"); - - final String output = CodeModelTestsHelper.declare (rec); - assertTrue (output.contains ("record Pair(T first, U second)")); - - CodeModelTestsHelper.parseCodeModel (cm); - } - - /** - * Test: Record with annotated component Expected output: - * - *
-   * public record Person (@NonNull String name, int age)
-   * {}
-   * 
- * - * @throws JCodeModelException - * In case of error - */ - @Test - public void testRecordWithAnnotatedComponent () throws JCodeModelException - { - final JCodeModel cm = new JCodeModel (); - final JDefinedClass rec = cm._package ("org.example")._record ("Person"); - - final JRecordComponent nameComponent = rec.recordComponent (cm.ref (String.class), "name"); - nameComponent.annotate (org.jspecify.annotations.NonNull.class); - - rec.recordComponent (cm.INT, "age"); - - final String output = CodeModelTestsHelper.declare (rec); - assertTrue (output.contains ("@org.jspecify.annotations.NonNull java.lang.String name")); - - CodeModelTestsHelper.parseCodeModel (cm); - } - - /** - * Test: Record with compact constructor (validation) Expected output: - * - *
-   * public record Range (int lo, int hi)
-   * {
-   *   public Range
-   *   {
-   *     if (lo > hi)
-   *     {
-   *       throw new IllegalArgumentException ();
-   *     }
-   *   }
-   * }
-   * 
- * - * @throws JCodeModelException - * In case of error - */ - @Test - public void testRecordWithCompactConstructor () throws JCodeModelException - { - final JCodeModel cm = new JCodeModel (); - final JDefinedClass rec = cm._package ("org.example")._record ("Range"); - final JRecordComponent rcLo = rec.recordComponent (cm.INT, "lo"); - final JRecordComponent rcHi = rec.recordComponent (cm.INT, "hi"); - - // Compact constructor - no parameter list, just validation logic - final JMethod compactCtor = rec.compactConstructor (JMod.PUBLIC); - compactCtor.body () - ._if (JExpr.ref (rcLo).gt (JExpr.ref (rcHi))) - ._then () - ._throw (cm.ref (IllegalArgumentException.class), JExpr.lit ("High must be greater or equal to Low")); - - final String output = CodeModelTestsHelper.declare (rec); - // Compact constructor has no parentheses after the record name - assertTrue (output.contains ("public Range {")); - - CodeModelTestsHelper.parseCodeModel (cm); - } - - /** - * Test: Record with explicit canonical constructor Expected output: - * - *
-   * public record Range (int lo, int hi)
-   * {
-   *   public Range (int lo, int hi)
-   *   {
-   *     if (lo > hi)
-   *     {
-   *       throw new IllegalArgumentException ();
-   *     }
-   *     this.lo = lo;
-   *     this.hi = hi;
-   *   }
-   * }
-   * 
- * - * @throws JCodeModelException - * In case of error - */ - @Test - public void testRecordWithCanonicalConstructor () throws JCodeModelException - { - final JCodeModel cm = new JCodeModel (); - final JDefinedClass rec = cm._package ("org.example")._record ("Range"); - final JRecordComponent rcLo = rec.recordComponent (cm.INT, "lo"); - final JRecordComponent rcHi = rec.recordComponent (cm.INT, "hi"); - - // Canonical constructor - must have same parameters as record components - final JMethod ctor = rec.constructor (JMod.PUBLIC); - final JVar loParam = ctor.param (cm.INT, "lo"); - final JVar hiParam = ctor.param (cm.INT, "hi"); - ctor.body ()._if (loParam.gt (hiParam))._then ()._throw (JExpr._new (cm.ref (IllegalArgumentException.class))); - // This could be done nicer... - ctor.body ().assign (JExpr.refthis (rcLo), loParam); - ctor.body ().assign (JExpr.refthis (rcHi), hiParam); - - final String output = CodeModelTestsHelper.declare (rec); - // Compact constructor has no parentheses after the record name - assertTrue (output.contains ("this.lo = lo;")); - assertTrue (output.contains ("this.hi = hi;")); - - CodeModelTestsHelper.parseCodeModel (cm); - } - - /** - * Test: Record with additional instance method Expected output: - * - *
-   * public record Point (int x, int y)
-   * {
-   *   public double distance ()
-   *   {
-   *     return Math.sqrt ((x * x) + (y * y));
-   *   }
-   * }
-   * 
- * - * @throws JCodeModelException - * In case of error - */ - @Test - public void testRecordWithMethod () throws JCodeModelException - { - final JCodeModel cm = new JCodeModel (); - final JDefinedClass rec = cm._package ("org.example")._record ("Point"); - final JRecordComponent rcX = rec.recordComponent (cm.INT, "x"); - final JRecordComponent rcY = rec.recordComponent (cm.INT, "y"); - - final JMethod method = rec.method (JMod.PUBLIC, cm.DOUBLE, "distance"); - method.body () - ._return (cm.ref (Math.class) - .staticInvoke ("sqrt") - .arg (JExpr.ref (rcX).mul (JExpr.ref (rcX)).plus (JExpr.ref (rcY).mul (JExpr.ref (rcY))))); - - CodeModelTestsHelper.parseCodeModel (cm); - } - - /** - * Test: Record with static field and method Expected output: - * - *
-   * public record Point (int x, int y)
-   * {
-   *   public static final Point ORIGIN = new Point (0, 0);
-   *
-   *   public static Point of (int x, int y)
-   *   {
-   *     return new Point (x, y);
-   *   }
-   * }
-   * 
- * - * @throws JCodeModelException - * In case of error - */ - @Test - public void testRecordWithStaticMembers () throws JCodeModelException - { - final JCodeModel cm = new JCodeModel (); - final JDefinedClass rec = cm._package ("org.example")._record ("Point"); - rec.recordComponent (cm.INT, "x"); - rec.recordComponent (cm.INT, "y"); - - // Static field - rec.field (JMod.PUBLIC | JMod.STATIC | JMod.FINAL, - rec, - "ORIGIN", - JExpr._new (rec).arg (JExpr.lit (0)).arg (JExpr.lit (0))); - - // Static factory method - final JMethod factory = rec.method (JMod.PUBLIC | JMod.STATIC, rec, "of"); - final JVar xParam = factory.param (cm.INT, "x"); - final JVar yParam = factory.param (cm.INT, "y"); - factory.body ()._return (JExpr._new (rec).arg (xParam).arg (yParam)); - - CodeModelTestsHelper.parseCodeModel (cm); - } - - /** - * Test: Nested record inside a class Expected output: - * - *
-   * public class Outer
-   * {
-   *   public record Inner (String value)
-   *   {}
-   * }
-   * 
- * - * @throws JCodeModelException - * In case of error - */ - @Test - public void testNestedRecord () throws JCodeModelException - { - final JCodeModel cm = new JCodeModel (); - final JDefinedClass outer = cm._package ("org.example")._class ("Outer"); - final JDefinedClass inner = outer._record (JMod.PUBLIC, "Inner"); - inner.recordComponent (cm.ref (String.class), "value"); - - final String output = CodeModelTestsHelper.declare (outer); - assertTrue (output.contains ("record Inner(java.lang.String value)")); - - CodeModelTestsHelper.parseCodeModel (cm); - } - - /** - * Test: Record with javadoc Expected output: - * - *
-   * /**
-   *  * Represents a 2D point.
-   *  *
-   *  * @param x the x coordinate
-   *  * @param y the y coordinate
-   *  *\/
-   * public record Point(int x, int y) {
-   * }
-   * 
- * - * @throws JCodeModelException - * In case of error - */ - @Test - public void testRecordWithJavadoc () throws JCodeModelException - { - final JCodeModel cm = new JCodeModel (); - final JDefinedClass rec = cm._package ("org.example")._record ("Point"); - - final JRecordComponent rcX = rec.recordComponent (cm.INT, "x"); - final JRecordComponent rcY = rec.recordComponent (cm.INT, "y"); - - rec.javadoc ().add ("Represents a 2D point."); - rec.javadoc ().addParam (rcX).add ("the x coordinate"); - rec.javadoc ().addParam (rcY).add ("the y coordinate"); - - final String output = CodeModelTestsHelper.declare (rec); - assertTrue (output.contains ("@param x\n * the x coordinate")); - assertTrue (output.contains ("@param y\n * the y coordinate")); - - CodeModelTestsHelper.parseCodeModel (cm); - } - - /** - * Test: Record with varargs component (last component can be varargs) Expected output: - * - *
-   * public record VarArgsRecord (String name, int... values)
-   * {}
-   * 
- * - * @throws JCodeModelException - * In case of error - */ - @Test - public void testRecordWithVarargsComponent () throws JCodeModelException - { - final JCodeModel cm = new JCodeModel (); - final JDefinedClass rec = cm._package ("org.example")._record ("VarArgsRecord"); - rec.recordComponent (cm.ref (String.class), "name"); - rec.recordComponentVararg (cm.INT, "values"); - - final String output = CodeModelTestsHelper.declare (rec); - assertTrue (output.contains ("int... values")); - - CodeModelTestsHelper.parseCodeModel (cm); - } - - /** - * Test: Record with array component Expected output: - * - *
-   * public record ArrayRecord (String [] names, int [] [] matrix)
-   * {}
-   * 
- * - * @throws JCodeModelException - * In case of error - */ - @Test - public void testRecordWithArrayComponent () throws JCodeModelException - { - final JCodeModel cm = new JCodeModel (); - final JDefinedClass rec = cm._package ("org.example")._record ("ArrayRecord"); - rec.recordComponent (cm.ref (String.class).array (), "names"); - rec.recordComponent (cm.INT.array ().array (), "matrix"); - - final String output = CodeModelTestsHelper.declare (rec); - assertTrue (output.contains ("String[] names")); - assertTrue (output.contains ("int[][] matrix")); - - CodeModelTestsHelper.parseCodeModel (cm); - } - - /** - * Test: Record with bounded generic type parameter Expected output: - * - *
-   * public record NumberPair <T extends Number> (T first, T second)
-   * {}
-   * 
- * - * @throws JCodeModelException - * In case of error - */ - @Test - public void testRecordWithBoundedTypeParameter () throws JCodeModelException - { - final JCodeModel cm = new JCodeModel (); - final JDefinedClass rec = cm._package ("org.example")._record ("NumberPair"); - final JTypeVar t = rec.generify ("T", Number.class); - rec.recordComponent (t, "first"); - rec.recordComponent (t, "second"); - - final String output = CodeModelTestsHelper.declare (rec); - assertTrue (output.contains ("")); - assertTrue (output.contains ("(T first, T second)")); - - CodeModelTestsHelper.parseCodeModel (cm); - } @Test (expected = IllegalStateException.class) public void testCantAddRecordComponentsToNonRecordClass () throws JCodeModelException diff --git a/jcodemodeltests/pom.xml b/jcodemodeltests/pom.xml new file mode 100644 index 00000000..ed2af35c --- /dev/null +++ b/jcodemodeltests/pom.xml @@ -0,0 +1,65 @@ + + 4.0.0 + + com.helger.jcodemodel + bom + 4.2.0-SNAPSHOT + ../bom + + JCodeModel-Tests + + + + com.helger + jcodemodel + + + junit + junit + test + + + + + + + org.codehaus.mojo + build-helper-maven-plugin + 3.6.1 + + + add-test-source + generate-test-sources + + add-test-source + + + + src/generated/javatest + + + + + + + org.codehaus.mojo + exec-maven-plugin + 3.6.3 + + + generatetestfiles + generate-test-sources + + java + + + ${project.basedir} + com.helger.jcodemodel.compile.annotation.GenerateTestFiles + + + + + + + + \ No newline at end of file diff --git a/jcodemodeltests/src/generated/javatest/com/helger/jcodemodel/tests/basic/Simple1.java b/jcodemodeltests/src/generated/javatest/com/helger/jcodemodel/tests/basic/Simple1.java new file mode 100644 index 00000000..5430b459 --- /dev/null +++ b/jcodemodeltests/src/generated/javatest/com/helger/jcodemodel/tests/basic/Simple1.java @@ -0,0 +1,4 @@ +package com.helger.jcodemodel.tests.basic; + +public class Simple1 { +} diff --git a/jcodemodeltests/src/generated/javatest/com/helger/jcodemodel/tests/basic/Simple2.java b/jcodemodeltests/src/generated/javatest/com/helger/jcodemodel/tests/basic/Simple2.java new file mode 100644 index 00000000..0e8eb028 --- /dev/null +++ b/jcodemodeltests/src/generated/javatest/com/helger/jcodemodel/tests/basic/Simple2.java @@ -0,0 +1,4 @@ +package com.helger.jcodemodel.tests.basic; + +public class Simple2 { +} diff --git a/jcodemodeltests/src/generated/javatest/com/helger/jcodemodel/tests/record/AnnotatedPerson.java b/jcodemodeltests/src/generated/javatest/com/helger/jcodemodel/tests/record/AnnotatedPerson.java new file mode 100644 index 00000000..f51a4744 --- /dev/null +++ b/jcodemodeltests/src/generated/javatest/com/helger/jcodemodel/tests/record/AnnotatedPerson.java @@ -0,0 +1,4 @@ +package com.helger.jcodemodel.tests.record; + +public record AnnotatedPerson(@JRecordTestGen.RecordAnnotationExample String name, int age) { +} diff --git a/jcodemodeltests/src/generated/javatest/com/helger/jcodemodel/tests/record/ArrayRecord.java b/jcodemodeltests/src/generated/javatest/com/helger/jcodemodel/tests/record/ArrayRecord.java new file mode 100644 index 00000000..7fc65df4 --- /dev/null +++ b/jcodemodeltests/src/generated/javatest/com/helger/jcodemodel/tests/record/ArrayRecord.java @@ -0,0 +1,4 @@ +package com.helger.jcodemodel.tests.record; + +public record ArrayRecord(String[] names, int[][] matrix) { +} diff --git a/jcodemodeltests/src/generated/javatest/com/helger/jcodemodel/tests/record/BasicPoint.java b/jcodemodeltests/src/generated/javatest/com/helger/jcodemodel/tests/record/BasicPoint.java new file mode 100644 index 00000000..8140ebd2 --- /dev/null +++ b/jcodemodeltests/src/generated/javatest/com/helger/jcodemodel/tests/record/BasicPoint.java @@ -0,0 +1,4 @@ +package com.helger.jcodemodel.tests.record; + +public record BasicPoint(int x, int y) { +} diff --git a/jcodemodeltests/src/generated/javatest/com/helger/jcodemodel/tests/record/Empty.java b/jcodemodeltests/src/generated/javatest/com/helger/jcodemodel/tests/record/Empty.java new file mode 100644 index 00000000..a5c9fe0c --- /dev/null +++ b/jcodemodeltests/src/generated/javatest/com/helger/jcodemodel/tests/record/Empty.java @@ -0,0 +1,4 @@ +package com.helger.jcodemodel.tests.record; + +public record Empty() { +} diff --git a/jcodemodeltests/src/generated/javatest/com/helger/jcodemodel/tests/record/NamedPoint.java b/jcodemodeltests/src/generated/javatest/com/helger/jcodemodel/tests/record/NamedPoint.java new file mode 100644 index 00000000..ebfce1ee --- /dev/null +++ b/jcodemodeltests/src/generated/javatest/com/helger/jcodemodel/tests/record/NamedPoint.java @@ -0,0 +1,10 @@ +package com.helger.jcodemodel.tests.record; + +public record NamedPoint(int x, int y, String name) + implements Comparable +{ + + public int compareTo(NamedPoint other) { + return 0; + } +} diff --git a/jcodemodeltests/src/generated/javatest/com/helger/jcodemodel/tests/record/Outer.java b/jcodemodeltests/src/generated/javatest/com/helger/jcodemodel/tests/record/Outer.java new file mode 100644 index 00000000..cc611f2c --- /dev/null +++ b/jcodemodeltests/src/generated/javatest/com/helger/jcodemodel/tests/record/Outer.java @@ -0,0 +1,7 @@ +package com.helger.jcodemodel.tests.record; + +public class Outer { + + public record Inner(String value) { + } +} diff --git a/jcodemodeltests/src/generated/javatest/com/helger/jcodemodel/tests/record/Pair.java b/jcodemodeltests/src/generated/javatest/com/helger/jcodemodel/tests/record/Pair.java new file mode 100644 index 00000000..bce9ef75 --- /dev/null +++ b/jcodemodeltests/src/generated/javatest/com/helger/jcodemodel/tests/record/Pair.java @@ -0,0 +1,4 @@ +package com.helger.jcodemodel.tests.record; + +public record Pair(T first, U second) { +} diff --git a/jcodemodeltests/src/generated/javatest/com/helger/jcodemodel/tests/record/PairNumber.java b/jcodemodeltests/src/generated/javatest/com/helger/jcodemodel/tests/record/PairNumber.java new file mode 100644 index 00000000..d6a4e52f --- /dev/null +++ b/jcodemodeltests/src/generated/javatest/com/helger/jcodemodel/tests/record/PairNumber.java @@ -0,0 +1,4 @@ +package com.helger.jcodemodel.tests.record; + +public record PairNumber(T first, T second) { +} diff --git a/jcodemodeltests/src/generated/javatest/com/helger/jcodemodel/tests/record/Person.java b/jcodemodeltests/src/generated/javatest/com/helger/jcodemodel/tests/record/Person.java new file mode 100644 index 00000000..e0348bc5 --- /dev/null +++ b/jcodemodeltests/src/generated/javatest/com/helger/jcodemodel/tests/record/Person.java @@ -0,0 +1,4 @@ +package com.helger.jcodemodel.tests.record; + +public record Person(String name, Integer age) { +} diff --git a/jcodemodeltests/src/generated/javatest/com/helger/jcodemodel/tests/record/PointDistance.java b/jcodemodeltests/src/generated/javatest/com/helger/jcodemodel/tests/record/PointDistance.java new file mode 100644 index 00000000..ac9aa6bd --- /dev/null +++ b/jcodemodeltests/src/generated/javatest/com/helger/jcodemodel/tests/record/PointDistance.java @@ -0,0 +1,8 @@ +package com.helger.jcodemodel.tests.record; + +public record PointDistance(int x, int y) { + + public double distance() { + return Math.sqrt(((x*x)+(y*y))); + } +} diff --git a/jcodemodeltests/src/generated/javatest/com/helger/jcodemodel/tests/record/PointJavadoc.java b/jcodemodeltests/src/generated/javatest/com/helger/jcodemodel/tests/record/PointJavadoc.java new file mode 100644 index 00000000..ff93f083 --- /dev/null +++ b/jcodemodeltests/src/generated/javatest/com/helger/jcodemodel/tests/record/PointJavadoc.java @@ -0,0 +1,13 @@ +package com.helger.jcodemodel.tests.record; + + +/** + * Represents a 2D point. + * + * @param x + * the x coordinate + * @param y + * the y coordinate + */ +public record PointJavadoc(int x, int y) { +} diff --git a/jcodemodeltests/src/generated/javatest/com/helger/jcodemodel/tests/record/PointStatic.java b/jcodemodeltests/src/generated/javatest/com/helger/jcodemodel/tests/record/PointStatic.java new file mode 100644 index 00000000..ca715f36 --- /dev/null +++ b/jcodemodeltests/src/generated/javatest/com/helger/jcodemodel/tests/record/PointStatic.java @@ -0,0 +1,9 @@ +package com.helger.jcodemodel.tests.record; + +public record PointStatic(int x, int y) { + public static final PointStatic ORIGIN = new PointStatic(0, 0); + + public static PointStatic of(int x, int y) { + return new PointStatic(x, y); + } +} diff --git a/jcodemodeltests/src/generated/javatest/com/helger/jcodemodel/tests/record/Range.java b/jcodemodeltests/src/generated/javatest/com/helger/jcodemodel/tests/record/Range.java new file mode 100644 index 00000000..1ce9f800 --- /dev/null +++ b/jcodemodeltests/src/generated/javatest/com/helger/jcodemodel/tests/record/Range.java @@ -0,0 +1,10 @@ +package com.helger.jcodemodel.tests.record; + +public record Range(int lo, int hi) { + + public Range { + if (lo >hi) { + throw new IllegalArgumentException("High must be greater or equal to Low"); + } + } +} diff --git a/jcodemodeltests/src/generated/javatest/com/helger/jcodemodel/tests/record/RangeCanonical.java b/jcodemodeltests/src/generated/javatest/com/helger/jcodemodel/tests/record/RangeCanonical.java new file mode 100644 index 00000000..9b343e89 --- /dev/null +++ b/jcodemodeltests/src/generated/javatest/com/helger/jcodemodel/tests/record/RangeCanonical.java @@ -0,0 +1,12 @@ +package com.helger.jcodemodel.tests.record; + +public record RangeCanonical(int lo, int hi) { + + public RangeCanonical(int lo, int hi) { + if (lo >hi) { + throw new IllegalArgumentException("lo must be < hi"); + } + this.lo = lo; + this.hi = hi; + } +} diff --git a/jcodemodeltests/src/generated/javatest/com/helger/jcodemodel/tests/record/SeriesVarArgs.java b/jcodemodeltests/src/generated/javatest/com/helger/jcodemodel/tests/record/SeriesVarArgs.java new file mode 100644 index 00000000..9bf22edc --- /dev/null +++ b/jcodemodeltests/src/generated/javatest/com/helger/jcodemodel/tests/record/SeriesVarArgs.java @@ -0,0 +1,4 @@ +package com.helger.jcodemodel.tests.record; + +public record SeriesVarArgs(String name, int... values) { +} diff --git a/jcodemodeltests/src/main/java/com/helger/jcodemodel/compile/annotation/GenerateTestFiles.java b/jcodemodeltests/src/main/java/com/helger/jcodemodel/compile/annotation/GenerateTestFiles.java new file mode 100644 index 00000000..b765bebb --- /dev/null +++ b/jcodemodeltests/src/main/java/com/helger/jcodemodel/compile/annotation/GenerateTestFiles.java @@ -0,0 +1,116 @@ +package com.helger.jcodemodel.compile.annotation; + +import java.io.File; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Stream; + +import com.helger.jcodemodel.JCodeModel; +import com.helger.jcodemodel.writer.JCMWriter; +import com.helger.jcodemodel.writer.ProgressCodeWriter.IProgressTracker; + +public class GenerateTestFiles { + + private static final String OUTPUT_DIR = "src/generated/javatest"; + + private static final String CLASS_SCAN_DIR = "src/main/java"; + + private final File outputDir; + + private final File classScanDir; + + public static void main(String[] args) { + String rootPath = args == null || args.length == 0 ? "." : args[0]; + File outputFile = new File(rootPath, OUTPUT_DIR); + File classScanDir = new File(rootPath, CLASS_SCAN_DIR); + new GenerateTestFiles(outputFile, classScanDir) + .apply(); + } + + public GenerateTestFiles(File outputDir, File classScanDir) { + this.outputDir = outputDir; + this.classScanDir = classScanDir; + } + + void apply() { + delete(outputDir); + outputDir.mkdirs(); + scanClasses(classScanDir).forEach(this::applyCandidateClass); + + } + + void delete(File file) { + if (file.isDirectory()) { + for (File sub : file.listFiles()) { + delete(sub); + } + } + file.delete(); + } + + Stream scanClasses(File rootDir) { + return scanClasses(rootDir, "", Stream.of()); + } + + Stream scanClasses(File dir, String packageName, Stream stream) { + List newFound = new ArrayList<>(); + if(!dir.isDirectory()) { + throw new RuntimeException("file " + dir.getAbsolutePath() + " expected to be a dir"); + } + for (File child : dir.listFiles()) { + if (child.isDirectory()) { + stream = scanClasses(child, (packageName.isEmpty() ? "" : packageName + ".") + child.getName(), stream); + + } else if (child.isFile() && child.getName().endsWith(".java")) { + newFound.add(packageName + "." + child.getName().replace(".java", "")); + } + } + if (!newFound.isEmpty()) { + stream = Stream.concat(stream, newFound.stream()); + } + return stream; + } + + void applyCandidateClass(String className) { + Class clazz; + try { + clazz = Class.forName(className); + if (clazz.getAnnotation(TestJCM.class) != null) { + runGeneration(clazz); + } + } catch (ClassNotFoundException | IllegalAccessException | IllegalArgumentException + | InvocationTargetException | InstantiationException | NoSuchMethodException | SecurityException + | IOException e) { + throw new RuntimeException(e); + } + } + + private void runGeneration(Class clazz) + throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException, + NoSuchMethodException, SecurityException, IOException { + for (Method m : clazz.getDeclaredMethods()) { + // only apply to methods public, with 0 args, and that produce a JCodeModel + if ((m.getModifiers() & Modifier.PUBLIC) > 0 + && m.getParameterCount() == 0) { + if (m.getReturnType().equals(JCodeModel.class)) { + m.setAccessible(true); + JCodeModel produced = null; + if ((m.getModifiers() & Modifier.STATIC) > 0) { + produced = (JCodeModel) m.invoke(null); + } else { + Object inst = clazz.getDeclaredConstructor().newInstance(); + produced = (JCodeModel) m.invoke(inst); + } + if (produced != null) { + new JCMWriter(produced).build(outputDir, (IProgressTracker) null); + } + } + } + } + } + +} diff --git a/jcodemodeltests/src/main/java/com/helger/jcodemodel/compile/annotation/TestJCM.java b/jcodemodeltests/src/main/java/com/helger/jcodemodel/compile/annotation/TestJCM.java new file mode 100644 index 00000000..e10bc6dd --- /dev/null +++ b/jcodemodeltests/src/main/java/com/helger/jcodemodel/compile/annotation/TestJCM.java @@ -0,0 +1,12 @@ +package com.helger.jcodemodel.compile.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface TestJCM { + +} diff --git a/jcodemodeltests/src/main/java/com/helger/jcodemodel/tests/basic/SimpleClassGenerating.java b/jcodemodeltests/src/main/java/com/helger/jcodemodel/tests/basic/SimpleClassGenerating.java new file mode 100644 index 00000000..2b698ce5 --- /dev/null +++ b/jcodemodeltests/src/main/java/com/helger/jcodemodel/tests/basic/SimpleClassGenerating.java @@ -0,0 +1,27 @@ +package com.helger.jcodemodel.tests.basic; + +import com.helger.jcodemodel.JCodeModel; +import com.helger.jcodemodel.compile.annotation.TestJCM; +import com.helger.jcodemodel.exceptions.JCodeModelException; + +@TestJCM +public class SimpleClassGenerating { + + public JCodeModel createSimple1() throws JCodeModelException { + JCodeModel cm = new JCodeModel(); + cm._class("com.helger.jcodemodel.tests.basic.Simple1"); + return cm; + } + + public JCodeModel createSimple2() throws JCodeModelException { + JCodeModel cm = new JCodeModel(); + cm._class("com.helger.jcodemodel.tests.basic.Simple2"); + return cm; + } + + /** protected so should not be selected */ + protected JCodeModel protectedCall() { + return null; + } + +} diff --git a/jcodemodeltests/src/main/java/com/helger/jcodemodel/tests/record/JRecordTestGen.java b/jcodemodeltests/src/main/java/com/helger/jcodemodel/tests/record/JRecordTestGen.java new file mode 100644 index 00000000..91c9d944 --- /dev/null +++ b/jcodemodeltests/src/main/java/com/helger/jcodemodel/tests/record/JRecordTestGen.java @@ -0,0 +1,410 @@ +package com.helger.jcodemodel.tests.record; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import com.helger.jcodemodel.JCodeModel; +import com.helger.jcodemodel.JDefinedClass; +import com.helger.jcodemodel.JExpr; +import com.helger.jcodemodel.JMethod; +import com.helger.jcodemodel.JMod; +import com.helger.jcodemodel.JRecordComponent; +import com.helger.jcodemodel.JTypeVar; +import com.helger.jcodemodel.JVar; +import com.helger.jcodemodel.compile.annotation.TestJCM; +import com.helger.jcodemodel.exceptions.JCodeModelException; + +@TestJCM +public class JRecordTestGen { + + public final String rootPackage=getClass().getPackageName(); + + /** + * Test: Basic record with two components Expected output: + * + *
+   * package org.example;
+   *
+   * public record Point(int x, int y) {
+   * }
+   * 
+ * + * @throws JCodeModelException + * In case of error + */ + public JCodeModel testBasicRecord() throws JCodeModelException + { + final JCodeModel cm = new JCodeModel (); + final JDefinedClass rec = cm._package (rootPackage)._record ("BasicPoint"); + rec.recordComponent (cm.INT, "x"); + rec.recordComponent (cm.INT, "y"); + return cm; + } + + /** + * Test: Empty record (no components) Expected output: + * + *
+   * public record Empty ()
+   * {}
+   * 
+ * + * @throws JCodeModelException + * In case of error + */ + public JCodeModel testEmptyRecord() throws JCodeModelException + { + final JCodeModel cm = new JCodeModel (); + cm._package(rootPackage)._record("Empty"); + return cm; + } + + /** + * Test: Record with object type components Expected output: + * + *
+   * public record Person (String name, Integer age)
+   * {}
+   * 
+ * + * @throws JCodeModelException + * In case of error + */ + public JCodeModel testRecordWithObjectComponents() throws JCodeModelException + { + final JCodeModel cm = new JCodeModel (); + final JDefinedClass rec = cm._package (rootPackage)._record ("Person"); + rec.recordComponent (cm.ref (String.class), "name"); + rec.recordComponent (cm.ref (Integer.class), "age"); + return cm; + } + + /** + * Test: Record implementing an interface Expected output: + * + *
+   * public record NamedPoint (int x, int y, String name) implements Comparable <NamedPoint>
+   * {}
+   * 
+ * + * @throws JCodeModelException + * In case of error + */ + public JCodeModel testRecordImplementsInterface() throws JCodeModelException + { + final JCodeModel cm = new JCodeModel (); + final JDefinedClass rec = cm._package (rootPackage)._record ("NamedPoint"); + rec.recordComponent (cm.INT, "x"); + rec.recordComponent (cm.INT, "y"); + rec.recordComponent (cm.ref (String.class), "name"); + rec._implements (cm.ref (Comparable.class).narrow (rec)); + JMethod cmp = rec.method(JMod.PUBLIC, cm.INT, "compareTo"); + cmp.param(rec, "other"); + cmp.body()._return(JExpr.lit(0)); + return cm; + } + + /** + * Test: Generic record with type parameters Expected output: + * + *
+   * public record Pair<T, U>(T first, U second) {
+   * }
+   * 
+ * + * @throws JCodeModelException + * In case of error + */ + public JCodeModel testGenericRecord() throws JCodeModelException + { + final JCodeModel cm = new JCodeModel(); + final JDefinedClass rec = cm._package(rootPackage)._record("Pair"); + final JTypeVar t = rec.generify("T"); + final JTypeVar u = rec.generify("U"); + rec.recordComponent(t, "first"); + rec.recordComponent(u, "second"); + return cm; + } + + /** + * Test: Record with bounded generic type parameter Expected output: + * + *
+   * public record NumberPair<T extends Number>(T first, T second) {
+   * }
+   * 
+ * + * @throws JCodeModelException + * In case of error + */ + public JCodeModel testRecordWithBoundedTypeParameter() throws JCodeModelException + { + final JCodeModel cm = new JCodeModel(); + final JDefinedClass rec = cm._package(rootPackage)._record("PairNumber"); + final JTypeVar t = rec.generify("T", Number.class); + rec.recordComponent(t, "first"); + rec.recordComponent(t, "second"); + return cm; + } + + /** + * Test: Record with annotated component Expected output: + * + *
+   * public record Person(@NonNull String name, int age) {
+   * }
+   * 
+ * + * @throws JCodeModelException + * In case of error + */ + public JCodeModel testRecordWithAnnotatedComponent() throws JCodeModelException + { + final JCodeModel cm = new JCodeModel(); + final JDefinedClass rec = cm._package(rootPackage)._record("AnnotatedPerson"); + final JRecordComponent nameComponent = rec.recordComponent(cm.ref(String.class), "name"); + nameComponent.annotate(RecordAnnotationExample.class); + rec.recordComponent(cm.INT, "age"); + return cm; + } + + /** + * we need a specific record annotation to be kept + */ + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.RECORD_COMPONENT) + public @interface RecordAnnotationExample + { + } + + /** + * Test: Record with compact constructor (validation) Expected output: + * + *
+   * public record Range(int lo, int hi) {
+   * 	public Range {
+   * 		if (lo > hi) {
+   * 			throw new IllegalArgumentException();
+   * 		}
+   * 	}
+   * }
+   * 
+ * + * @throws JCodeModelException + * In case of error + */ + public JCodeModel testRecordWithCompactConstructor() throws JCodeModelException + { + final JCodeModel cm = new JCodeModel(); + final JDefinedClass rec = cm._package(rootPackage)._record("Range"); + final JRecordComponent rcLo = rec.recordComponent(cm.INT, "lo"); + final JRecordComponent rcHi = rec.recordComponent(cm.INT, "hi"); + + // Compact constructor - no parameter list, just validation logic + final JMethod compactCtor = rec.compactConstructor(JMod.PUBLIC); + compactCtor.body() + ._if(JExpr.ref(rcLo).gt(JExpr.ref(rcHi))) + ._then() + ._throw(cm.ref(IllegalArgumentException.class), JExpr.lit("High must be greater or equal to Low")); + return cm; + } + + /** + * Test: Record with explicit canonical constructor Expected output: + * + *
+   * public record Range(int lo, int hi) {
+   * 	public Range(int lo, int hi) {
+   * 		if (lo > hi) {
+   * 			throw new IllegalArgumentException();
+   * 		}
+   * 		this.lo = lo;
+   * 		this.hi = hi;
+   * 	}
+   * }
+   * 
+ * + * @throws JCodeModelException + * In case of error + */ + public JCodeModel testRecordWithCanonicalConstructor() throws JCodeModelException + { + final JCodeModel cm = new JCodeModel(); + final JDefinedClass rec = cm._package(rootPackage)._record("RangeCanonical"); + final JRecordComponent rcLo = rec.recordComponent(cm.INT, "lo"); + final JRecordComponent rcHi = rec.recordComponent(cm.INT, "hi"); + + // Canonical constructor - must have same parameters as record components + final JMethod ctor = rec.constructor(JMod.PUBLIC); + final JVar loParam = ctor.param(cm.INT, "lo"); + final JVar hiParam = ctor.param(cm.INT, "hi"); + ctor.body()._if(loParam.gt(hiParam))._then() + ._throw(cm.ref(IllegalArgumentException.class), + JExpr.lit("lo must be < hi")); + ctor.body().assign(JExpr.refthis(rcLo), loParam); + ctor.body().assign(JExpr.refthis(rcHi), hiParam); + return cm; + } + + /** + * Test: Record with additional instance method Expected output: + * + *
+   * public record Point (int x, int y)
+   * {
+   *   public double distance ()
+   *   {
+   *     return Math.sqrt ((x * x) + (y * y));
+   *   }
+   * }
+   * 
+ * + * @throws JCodeModelException + * In case of error + */ + public JCodeModel testRecordWithMethod () throws JCodeModelException + { + final JCodeModel cm = new JCodeModel (); + final JDefinedClass rec = cm._package(rootPackage)._record("PointDistance"); + final JRecordComponent rcX = rec.recordComponent (cm.INT, "x"); + final JRecordComponent rcY = rec.recordComponent (cm.INT, "y"); + + final JMethod method = rec.method (JMod.PUBLIC, cm.DOUBLE, "distance"); + method.body () + ._return (cm.ref (Math.class) + .staticInvoke ("sqrt") + .arg (JExpr.ref (rcX).mul (JExpr.ref (rcX)).plus (JExpr.ref (rcY).mul (JExpr.ref (rcY))))); + return cm; + } + + /** + * Test: Record with static field and method Expected output: + * + *
+   * public record Point(int x, int y) {
+   * 	public static final Point ORIGIN = new Point(0, 0);
+   *
+   * 	public static Point of(int x, int y) {
+   * 		return new Point(x, y);
+   * 	}
+   * }
+   * 
+ * + * @throws JCodeModelException + * In case of error + */ + public JCodeModel testRecordWithStaticMembers() throws JCodeModelException + { + final JCodeModel cm = new JCodeModel(); + final JDefinedClass rec = cm._package(rootPackage)._record("PointStatic"); + rec.recordComponent(cm.INT, "x"); + rec.recordComponent(cm.INT, "y"); + + // Static field + rec.field(JMod.PUBLIC | JMod.STATIC | JMod.FINAL, + rec, + "ORIGIN", + JExpr._new(rec).arg(JExpr.lit(0)).arg(JExpr.lit(0))); + + // Static factory method + final JMethod factory = rec.method(JMod.PUBLIC | JMod.STATIC, rec, "of"); + final JVar xParam = factory.param(cm.INT, "x"); + final JVar yParam = factory.param(cm.INT, "y"); + factory.body()._return(JExpr._new(rec).arg(xParam).arg(yParam)); + return cm; + } + + /** + * Test: Nested record inside a class Expected output: + * + *
+   * public class Outer {
+   * 	public record Inner(String value) {
+   * 	}
+   * }
+   * 
+ * + * @throws JCodeModelException + * In case of error + */ + public JCodeModel testNestedRecord() throws JCodeModelException + { + final JCodeModel cm = new JCodeModel(); + final JDefinedClass outer = cm._package(rootPackage)._class("Outer"); + final JDefinedClass inner = outer._record(JMod.PUBLIC, "Inner"); + inner.recordComponent(cm.ref(String.class), "value"); + return cm; + } + + /** + * Test: Record with javadoc Expected output: + * + *
+   * /**
+   *  * Represents a 2D point.
+   *  *
+   *  * @param x the x coordinate
+   *  * @param y the y coordinate
+   *  *\/
+   * public record Point(int x, int y) {
+   * }
+   * 
+ * + * @throws JCodeModelException + * In case of error + */ + public JCodeModel testRecordWithJavadoc() throws JCodeModelException + { + final JCodeModel cm = new JCodeModel(); + final JDefinedClass rec = cm._package(rootPackage)._record("PointJavadoc"); + final JRecordComponent rcX = rec.recordComponent(cm.INT, "x"); + final JRecordComponent rcY = rec.recordComponent(cm.INT, "y"); + rec.javadoc().add("Represents a 2D point."); + rec.javadoc().addParam(rcX).add("the x coordinate"); + rec.javadoc().addParam(rcY).add("the y coordinate"); + return cm; + } + + /** + * Test: Record with varargs component (last component can be varargs) Expected + * output: + * + *
+   * public record VarArgsRecord(String name, int... values) {
+   * }
+   * 
+ * + * @throws JCodeModelException + * In case of error + */ + public JCodeModel testRecordWithVarargsComponent() throws JCodeModelException + { + final JCodeModel cm = new JCodeModel(); + final JDefinedClass rec = cm._package(rootPackage)._record("SeriesVarArgs"); + rec.recordComponent(cm.ref(String.class), "name"); + rec.recordComponentVararg(cm.INT, "values"); + return cm; + } + + /** + * Test: Record with array component Expected output: + * + *
+   * public record ArrayRecord(String[] names, int[][] matrix) {
+   * }
+   * 
+ * + * @throws JCodeModelException + * In case of error + */ + public JCodeModel testRecordWithArrayComponent() throws JCodeModelException { + final JCodeModel cm = new JCodeModel(); + final JDefinedClass rec = cm._package(rootPackage)._record("ArrayRecord"); + rec.recordComponent(cm.ref(String.class).array(), "names"); + rec.recordComponent(cm.INT.array().array(), "matrix"); + return cm; + } + +} diff --git a/jcodemodeltests/src/test/java/com/helger/jcodemodel/tests/basic/TestBasic.java b/jcodemodeltests/src/test/java/com/helger/jcodemodel/tests/basic/TestBasic.java new file mode 100644 index 00000000..1ae76d35 --- /dev/null +++ b/jcodemodeltests/src/test/java/com/helger/jcodemodel/tests/basic/TestBasic.java @@ -0,0 +1,13 @@ +package com.helger.jcodemodel.tests.basic; + +import org.junit.Test; + +public class TestBasic { + + @Test + public void testBasic() { + new Simple1(); + new Simple2(); + } + +} diff --git a/jcodemodeltests/src/test/java/com/helger/jcodemodel/tests/record/JRecordTest.java b/jcodemodeltests/src/test/java/com/helger/jcodemodel/tests/record/JRecordTest.java new file mode 100644 index 00000000..79b91d11 --- /dev/null +++ b/jcodemodeltests/src/test/java/com/helger/jcodemodel/tests/record/JRecordTest.java @@ -0,0 +1,241 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright (c) 1997-2010 Oracle and/or its affiliates. All rights reserved. + * Portions Copyright 2013-2026 Philip Helger + contributors + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common Development + * and Distribution License("CDDL") (collectively, the "License"). You + * may not use this file except in compliance with the License. You can + * obtain a copy of the License at + * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html + * or packager/legal/LICENSE.txt. See the License for the specific + * language governing permissions and limitations under the License. + * + * When distributing the software, include this License Header Notice in each + * file and include the License file at packager/legal/LICENSE.txt. + * + * GPL Classpath Exception: + * Oracle designates this particular file as subject to the "Classpath" + * exception as provided by Oracle in the GPL Version 2 section of the License + * file that accompanied this code. + * + * Modifications: + * If applicable, add the following below the License Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyright [year] [name of copyright owner]" + * + * Contributor(s): + * If you wish your version of this file to be governed by only the CDDL or + * only the GPL Version 2, indicate your decision by adding "[Contributor] + * elects to include this software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice of license, a + * recipient has the option to distribute your version of this file under + * either the CDDL, the GPL Version 2 or to extend the choice of license to + * its licensees as provided above. However, if you add GPL Version 2 code + * and therefore, elected the GPL Version 2 license, then the option applies + * only if the new code is made subject to such option by the copyright + * holder. + */ +package com.helger.jcodemodel.tests.record; + +import java.lang.reflect.RecordComponent; +import java.math.BigDecimal; +import java.util.stream.Stream; + +import org.junit.Assert; +import org.junit.Test; + +import com.helger.jcodemodel.tests.record.*; +import com.helger.jcodemodel.tests.record.JRecordTestGen.RecordAnnotationExample; +import com.helger.jcodemodel.tests.record.Outer.Inner; + +/** + * Test class for Java record support. Java records (JEP 395, Java 16+) are a special kind of class + * that acts as a transparent carrier for immutable data. Records automatically provide: - A + * canonical constructor - Private final fields for each component - Public accessor methods for + * each component (same name as component) - equals(), hashCode(), and toString() implementations + */ +public final class JRecordTest +{ + + /** + * tests {@link JRecordTestGen#testBasicRecord()} + */ + @Test + public void testBasicRecord() + { + BasicPoint test = new BasicPoint(2, 3); + Assert.assertTrue(test instanceof Record); + Assert.assertEquals(2, test.x()); + Assert.assertEquals(3, test.y()); + } + + /** + * tests {@link JRecordTestGen#testEmptyRecord()} + */ + @Test + public void testEmptyRecord() + { + Empty test = new Empty(); + Assert.assertTrue(test instanceof Record); + } + + /** + * tests {@link JRecordTestGen#testRecordWithObjectComponents()} + */ + @Test + public void testRecordWithObjectComponents() + { + Person test = new Person("John", 42); + Assert.assertTrue(test instanceof Record); + Assert.assertEquals((Integer) 42, test.age()); + Assert.assertEquals("John", test.name()); + } + + /** + * tests {@link JRecordTestGen#testRecordImplementsInterface()} + */ + @Test + public void testRecordImplementsInterface() + { + NamedPoint test = new NamedPoint(5, 10, "15"); + Assert.assertTrue(test instanceof Record); + Assert.assertTrue(test instanceof Comparable); + Assert.assertEquals("15", test.name()); + Assert.assertEquals(5, test.x()); + Assert.assertEquals(10, test.y()); + } + + /** + * tests {@link JRecordTestGen#testGenericRecord()} + */ + @Test + public void testGenericRecord() + { + Pair test = new Pair<>(666, "BE NOT AFRAID"); + Assert.assertTrue(test instanceof Record); + Assert.assertEquals((Integer) 666, test.first()); + Assert.assertEquals("BE NOT AFRAID", test.second()); + } + + /** + * tests {@link JRecordTestGen#testRecordWithBoundedTypeParameter()} + */ + @Test + public void testRecordWithBoundedTypeParameter() + { + PairNumber test = new PairNumber<>(BigDecimal.ONE, BigDecimal.ZERO); + Assert.assertTrue(test instanceof Record); + } + + /** + * tests {@link JRecordTestGen#testRecordWithAnnotatedComponent()} + * + * @throws SecurityException + * @throws NoSuchFieldException + */ + @Test + public void testRecordWithAnnotatedComponent() + { + AnnotatedPerson test = new AnnotatedPerson("Salomon", 2000); + Assert.assertTrue(test instanceof Record); + + RecordComponent fieldComponent = Stream.of(test.getClass().getRecordComponents()) + .filter(rc -> rc.getName().equals("name")) + .findFirst().get(); + Assert.assertTrue(fieldComponent.isAnnotationPresent(RecordAnnotationExample.class)); + } + + /** + * tests {@link JRecordTestGen#testRecordWithCompactConstructor()} + */ + @Test + public void testRecordWithCompactConstructor() + { + Range test = new Range(1, 5); + Assert.assertTrue(test instanceof Record); + Assert.assertThrows(IllegalArgumentException.class, () -> new Range(5, 1)); + } + + /** + * tests {@link JRecordTestGen#testRecordWithCanonicalConstructor()} + */ + @Test + public void testRecordWithCanonicalConstructor() + { + RangeCanonical test = new RangeCanonical(1, 5); + Assert.assertTrue(test instanceof Record); + Assert.assertThrows(IllegalArgumentException.class, () -> new RangeCanonical(5, 1)); + } + + /** + * tests {@link JRecordTestGen#testRecordWithMethod()} + */ + @Test + public void testRecordWithMethod () + { + PointDistance test = new PointDistance(0, 0); + Assert.assertTrue(test instanceof Record); + Assert.assertEquals(0, test.distance(), 0.0); + } + + /** + * tests {@link JRecordTestGen#testRecordWithStaticMembers()} + */ + @Test + public void testRecordWithStaticMembers() + { + PointStatic test = PointStatic.ORIGIN; + Assert.assertTrue(test instanceof Record); + test = PointStatic.of(6, 78); + Assert.assertEquals(6, test.x()); + Assert.assertEquals(78, test.y()); + } + + /** + * tests {@link JRecordTestGen#testNestedRecord()} + */ + @Test + public void testNestedRecord() + { + Inner test = new Inner("NaN"); + Assert.assertTrue(test instanceof Record); + Assert.assertEquals("NaN", test.value()); + } + + /** + * tests {@link JRecordTestGen#testRecordWithJavadoc()} + */ + @Test + public void testRecordWithJavadoc() { + // nothing to do to test javadoc ?? + PointJavadoc test = new PointJavadoc(0, 0); + Assert.assertTrue(test instanceof Record); + } + + /** + * tests {@link JRecordTestGen#testRecordWithVarargsComponent()} + */ + @Test + public void testRecordWithVarargsComponent() + { + SeriesVarArgs test = new SeriesVarArgs("Fibonacci", 1,1,3,4); + Assert.assertTrue(test instanceof Record); + Assert.assertArrayEquals(test.values(), new int[] { 1, 1, 3, 4 }); + } + + /** + * tests {@link JRecordTestGen#testRecordWithArrayComponent()} + */ + @Test + public void testRecordWithArrayComponent() { + ArrayRecord test = new ArrayRecord(new String[] { "id" }, new int[][] { { 1, 2 } }); + Assert.assertTrue(test instanceof Record); + Assert.assertArrayEquals(test.names(), new String[] { "id" }); + Assert.assertArrayEquals(test.matrix()[0], new int[] { 1, 2 }); + + } + +} 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 index cc5e8e0c..2763fa00 100644 --- 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 @@ -56,7 +56,6 @@ protected JsonPackage load (InputStream source) throws IOException protected Stream visitPackage (JsonPackage pck, String path) { - System.err.println ("visit package " + path); Stream ret = Stream.empty (); if (pck.isClassInfo ()) { diff --git a/plugin/pom.xml b/plugin/pom.xml index 2492d07d..30347dbd 100644 --- a/plugin/pom.xml +++ b/plugin/pom.xml @@ -19,8 +19,9 @@ 4.0.0 com.helger.jcodemodel - jcodemodel-parent-pom + bom 4.2.0-SNAPSHOT + ../bom plugin pom diff --git a/pom.xml b/pom.xml index 2cd9d6a3..f46d1649 100644 --- a/pom.xml +++ b/pom.xml @@ -112,9 +112,11 @@ + bom jcodemodel plugin examples + jcodemodeltests @@ -127,25 +129,7 @@ pom import - - - - com.helger - jcodemodel - ${project.version} -
- - - - - com.helger.jcodemodel - jcodemodel-maven-plugin - ${project.version} - - - -