Skip to content

Commit

Permalink
Support @GeneratePojobuilder on records
Browse files Browse the repository at this point in the history
  • Loading branch information
michi committed Jan 16, 2022
1 parent bee5537 commit cdaf7bf
Show file tree
Hide file tree
Showing 11 changed files with 465 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public InputFactory(Types types, DirectivesFactory directivesFactory) {
}

public Input getInput(Element annotatedElement) {
if (annotatedElement.getKind() == ElementKind.CLASS) {
if (annotatedElement.getKind() == ElementKind.CLASS || "RECORD".equals(annotatedElement.getKind().name())) {
TypeElement typeEl = (TypeElement) annotatedElement;
if (typeEl.getModifiers().contains(Modifier.PRIVATE)) {
throw new InvalidElementException(String.format("Pojo %s must not be private!", annotatedElement),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,8 @@ private void scanSourceCode(Input input, Output result) {
pojoConstructorScanner.scan((ExecutableElement) input.getAnnotatedElement(), result);
} else if (input.getAnnotatedElement().getKind() == ElementKind.METHOD) {
factoryMethodScanner.scan((ExecutableElement) input.getAnnotatedElement(), result);
} else if (input.getAnnotatedElement().getKind() == ElementKind.CLASS) {
} else if (input.getAnnotatedElement().getKind() == ElementKind.CLASS
|| "RECORD".equals(input.getAnnotatedElement().getKind().name())) {
TypeElement cls = (TypeElement) input.getAnnotatedElement();
pojoConstructorScanner.scan(cls, result);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

public abstract class TestBase {
public static final String TESTDATA_DIRECTORY = "src/testdata/java";
public static final String TESTDATA_DIRECTORY_JAVA16 = "src/testdata-java16/resources";

private static final boolean DEBUG_LOG_ENABLED = false;

Expand Down
84 changes: 84 additions & 0 deletions src/test/java/samples/AnnotationProcessor_Samples_Test.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
package samples;

import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assume.assumeTrue;

import java.io.File;
import java.net.URL;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.lang.model.SourceVersion;

import net.karneim.pojobuilder.processor.AnnotationProcessor;
import net.karneim.pojobuilder.processor.with.ProcessorTestSupport;
Expand Down Expand Up @@ -345,4 +349,84 @@ public void testShouldGenerateGregorianCalendarBuilder() throws Exception {
assertThat(actual).isEqualTo(expected);
assertThat(prj.findClass(builderClassname)).isNotNull();
}


private void assumeJdkSupportsAtLeastSourceVersion(int minimumSourceVersion) {
String latestSourceVersion = SourceVersion.latest().name();
Matcher m = Pattern.compile("^RELEASE_(\\d+)$").matcher(latestSourceVersion);
if (m.find()) {
int sourceVersion = Integer.valueOf(m.group(1));
if (sourceVersion >= minimumSourceVersion) {
return;
}
}
String jreVersion = System.getProperty("java.version");
String msg = "JRE " + jreVersion + " does not support records";
// better than throwing a Junit4 internal exception
assumeTrue(msg, false);
}

/**
* @scenario Generating a builder for a record.
* <p>
* This test will be skipped if the current JRE does not support RELEASE_16
* as source version.
* @throws Exception
*/
@Test
public void testShouldGenerateRecordBuilder() throws Exception {
assumeJdkSupportsAtLeastSourceVersion(16);

// Given:
String pojoClassname = "samples.Record";
String builderClassname = "samples.RecordBuilder";
prj.addSourceFile(getSourceFilename(TESTDATA_DIRECTORY_JAVA16, pojoClassname));

// When:
boolean success = prj.compile();

// Then:
assertThat(success).isTrue();
String actual = getContent(prj.findGeneratedSource(builderClassname));
logDebug(actual);

String expected = loadJavaSourceFromFilesystem(TESTDATA_DIRECTORY_JAVA16, builderClassname);
assertThat(actual).isEqualTo(expected);
assertThat(prj.findClass(builderClassname)).isNotNull();
}

/**
* @scenario Generating a builder for a record.
* <p>
* This test will be skipped if the current JRE does not support RELEASE_16
* as source version.
* @throws Exception
*/
@Test
public void testShouldGenerateRecordsInUmbrellaClass() throws Exception {
assumeJdkSupportsAtLeastSourceVersion(16);

// Given:
String umbrellaClassname = "samples.RecordsInUmbrellaClass";
String fooBuilderClassname = "samples.FooBuilder";
String barBuilderClassname = "samples.BarBuilder";
prj.addSourceFile(getSourceFilename(TESTDATA_DIRECTORY_JAVA16, umbrellaClassname));

// When:
boolean success = prj.compile();

// Then:
assertThat(success).isTrue();
String actualFooBuilder = getContent(prj.findGeneratedSource(fooBuilderClassname));
logDebug(actualFooBuilder);
String expectedFooBuilder = loadJavaSourceFromFilesystem(TESTDATA_DIRECTORY_JAVA16, fooBuilderClassname);
assertThat(actualFooBuilder).isEqualTo(expectedFooBuilder);
assertThat(prj.findClass(fooBuilderClassname)).isNotNull();

String actualBarBuilder = getContent(prj.findGeneratedSource(barBuilderClassname));
logDebug(actualBarBuilder);
String expectedBarBuilder = loadJavaSourceFromFilesystem(TESTDATA_DIRECTORY_JAVA16, barBuilderClassname);
assertThat(actualBarBuilder).isEqualTo(expectedBarBuilder);
assertThat(prj.findClass(barBuilderClassname)).isNotNull();
}
}
74 changes: 74 additions & 0 deletions src/testdata-java16/resources/samples/BarBuilder.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package samples;

import javax.annotation.processing.Generated;
import net.karneim.pojobuilder.GwtIncompatible;

@Generated("PojoBuilder")
public class BarBuilder
implements Cloneable {
protected BarBuilder self;
protected RecordsInUmbrellaClass.Foo value$foo$samples$RecordsInUmbrellaClass$Foo;
protected boolean isSet$foo$samples$RecordsInUmbrellaClass$Foo;

/**
* Creates a new {@link BarBuilder}.
*/
public BarBuilder() {
self = (BarBuilder)this;
}

/**
* Sets the default value for the foo property.
*
* @param value the default value
* @return this builder
*/
public BarBuilder withFoo(RecordsInUmbrellaClass.Foo value) {
this.value$foo$samples$RecordsInUmbrellaClass$Foo = value;
this.isSet$foo$samples$RecordsInUmbrellaClass$Foo = true;
return self;
}

/**
* Returns a clone of this builder.
*
* @return the clone
*/
@Override
@GwtIncompatible
public Object clone() {
try {
BarBuilder result = (BarBuilder)super.clone();
result.self = result;
return result;
} catch (CloneNotSupportedException e) {
throw new InternalError(e.getMessage());
}
}

/**
* Returns a clone of this builder.
*
* @return the clone
*/
@GwtIncompatible
public BarBuilder but() {
return (BarBuilder)clone();
}

/**
* Creates a new {@link RecordsInUmbrellaClass.Bar} based on this builder's settings.
*
* @return the created RecordsInUmbrellaClass.Bar
*/
public RecordsInUmbrellaClass.Bar build() {
try {
RecordsInUmbrellaClass.Bar result = new RecordsInUmbrellaClass.Bar(value$foo$samples$RecordsInUmbrellaClass$Foo);
return result;
} catch (RuntimeException ex) {
throw ex;
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
}
74 changes: 74 additions & 0 deletions src/testdata-java16/resources/samples/FooBuilder.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package samples;

import javax.annotation.processing.Generated;
import net.karneim.pojobuilder.GwtIncompatible;

@Generated("PojoBuilder")
public class FooBuilder
implements Cloneable {
protected FooBuilder self;
protected int value$foo$int;
protected boolean isSet$foo$int;

/**
* Creates a new {@link FooBuilder}.
*/
public FooBuilder() {
self = (FooBuilder)this;
}

/**
* Sets the default value for the foo property.
*
* @param value the default value
* @return this builder
*/
public FooBuilder withFoo(int value) {
this.value$foo$int = value;
this.isSet$foo$int = true;
return self;
}

/**
* Returns a clone of this builder.
*
* @return the clone
*/
@Override
@GwtIncompatible
public Object clone() {
try {
FooBuilder result = (FooBuilder)super.clone();
result.self = result;
return result;
} catch (CloneNotSupportedException e) {
throw new InternalError(e.getMessage());
}
}

/**
* Returns a clone of this builder.
*
* @return the clone
*/
@GwtIncompatible
public FooBuilder but() {
return (FooBuilder)clone();
}

/**
* Creates a new {@link RecordsInUmbrellaClass.Foo} based on this builder's settings.
*
* @return the created RecordsInUmbrellaClass.Foo
*/
public RecordsInUmbrellaClass.Foo build() {
try {
RecordsInUmbrellaClass.Foo result = new RecordsInUmbrellaClass.Foo(value$foo$int);
return result;
} catch (RuntimeException ex) {
throw ex;
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
}
6 changes: 6 additions & 0 deletions src/testdata-java16/resources/samples/Record.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package samples;

import net.karneim.pojobuilder.GeneratePojoBuilder;

@GeneratePojoBuilder
public record Record(String name, User assignee, String description) {}
102 changes: 102 additions & 0 deletions src/testdata-java16/resources/samples/RecordBuilder.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package samples;

import javax.annotation.processing.Generated;
import net.karneim.pojobuilder.GwtIncompatible;

@Generated("PojoBuilder")
public class RecordBuilder
implements Cloneable {
protected RecordBuilder self;
protected String value$name$java$lang$String;
protected boolean isSet$name$java$lang$String;
protected User value$assignee$samples$User;
protected boolean isSet$assignee$samples$User;
protected String value$description$java$lang$String;
protected boolean isSet$description$java$lang$String;

/**
* Creates a new {@link RecordBuilder}.
*/
public RecordBuilder() {
self = (RecordBuilder)this;
}

/**
* Sets the default value for the name property.
*
* @param value the default value
* @return this builder
*/
public RecordBuilder withName(String value) {
this.value$name$java$lang$String = value;
this.isSet$name$java$lang$String = true;
return self;
}

/**
* Sets the default value for the assignee property.
*
* @param value the default value
* @return this builder
*/
public RecordBuilder withAssignee(User value) {
this.value$assignee$samples$User = value;
this.isSet$assignee$samples$User = true;
return self;
}

/**
* Sets the default value for the description property.
*
* @param value the default value
* @return this builder
*/
public RecordBuilder withDescription(String value) {
this.value$description$java$lang$String = value;
this.isSet$description$java$lang$String = true;
return self;
}

/**
* Returns a clone of this builder.
*
* @return the clone
*/
@Override
@GwtIncompatible
public Object clone() {
try {
RecordBuilder result = (RecordBuilder)super.clone();
result.self = result;
return result;
} catch (CloneNotSupportedException e) {
throw new InternalError(e.getMessage());
}
}

/**
* Returns a clone of this builder.
*
* @return the clone
*/
@GwtIncompatible
public RecordBuilder but() {
return (RecordBuilder)clone();
}

/**
* Creates a new {@link Record} based on this builder's settings.
*
* @return the created Record
*/
public Record build() {
try {
Record result = new Record(value$name$java$lang$String, value$assignee$samples$User, value$description$java$lang$String);
return result;
} catch (RuntimeException ex) {
throw ex;
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
}
Loading

0 comments on commit cdaf7bf

Please sign in to comment.