Skip to content

Commit

Permalink
Merge pull request #419 from Ladicek/add-canonical-constructor
Browse files Browse the repository at this point in the history
add ClassInfo.canonicalConstructor()
  • Loading branch information
Ladicek authored Aug 8, 2024
2 parents b61ac9e + e57ef34 commit 6b0f3e3
Show file tree
Hide file tree
Showing 11 changed files with 217 additions and 0 deletions.
44 changes: 44 additions & 0 deletions core/src/main/java/org/jboss/jandex/ClassInfo.java
Original file line number Diff line number Diff line change
Expand Up @@ -746,6 +746,50 @@ public final List<MethodInfo> constructors() {
return constructors;
}

/**
* Returns the canonical constructor of this record. If this class is not a record, returns {@code null}.
* <p>
* Note that this method has the same limitations as {@link #unsortedRecordComponents()}. That is,
* at most 256 record components may be present, and an assumption is made that bytecode order
* of record components corresponds to the declaration order.
*
* @return the canonical constructor of this record, or {@code null} if this class is not a record
*/
public MethodInfo canonicalConstructor() {
if (!isRecord()) {
return null;
}

RecordComponentInternal[] recordComponents = recordComponentArray();
byte[] recordComponentPositions = recordComponentPositionArray();

if (recordComponents.length == recordComponentPositions.length) {
outer: for (MethodInternal method : methods) {
if (!Arrays.equals(Utils.INIT_METHOD_NAME, method.nameBytes())) {
// not a constructor
continue;
}

Type[] parameters = method.parameterTypesArray();
if (parameters.length != recordComponents.length) {
// not a constructor with the right number of parameters
continue;
}

for (int i = 0; i < parameters.length; i++) {
if (!parameters[i].equals(recordComponents[recordComponentPositions[i] & 0xFF].type())) {
// not a constructor with matching parameter types
continue outer;
}
}

return new MethodInfo(this, method);
}
}

throw new IllegalStateException("Could not determine the canonical constructor");
}

final MethodInternal[] methodArray() {
return methods;
}
Expand Down
60 changes: 60 additions & 0 deletions core/src/test/java/org/jboss/jandex/test/RecordTestCase.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,11 @@
import org.jboss.jandex.AnnotationInstance;
import org.jboss.jandex.AnnotationTarget;
import org.jboss.jandex.ClassInfo;
import org.jboss.jandex.ClassType;
import org.jboss.jandex.DotName;
import org.jboss.jandex.Index;
import org.jboss.jandex.Indexer;
import org.jboss.jandex.PrimitiveType;
import org.jboss.jandex.RecordComponentInfo;
import org.jboss.jandex.test.util.IndexingUtil;
import org.junit.jupiter.api.BeforeEach;
Expand Down Expand Up @@ -152,6 +154,53 @@ public void testRecordSignatureProcessed() {
assertEquals("T", rec.typeParameters().get(0).identifier());
}

@Test
public void canonicalCtor() {
ClassInfo rec = index.getClassByName("test.RecordWithNoComponentsAndDefaultCanonicalCtor");
assertEquals(1, rec.constructors().size());
assertEquals(rec.constructors().get(0), rec.canonicalConstructor());

rec = index.getClassByName("test.RecordWithNoComponentsAndCompactCanonicalCtor");
assertEquals(1, rec.constructors().size());
assertEquals(rec.constructors().get(0), rec.canonicalConstructor());

rec = index.getClassByName("test.RecordWithNoComponentsAndCustomCanonicalCtor");
assertEquals(1, rec.constructors().size());
assertEquals(rec.constructors().get(0), rec.canonicalConstructor());

rec = index.getClassByName("test.RecordWithDefaultCanonicalCtor");
assertEquals(1, rec.constructors().size());
assertEquals(rec.constructors().get(0), rec.canonicalConstructor());

rec = index.getClassByName("test.RecordWithCompactCanonicalCtor");
assertEquals(1, rec.constructors().size());
assertEquals(rec.constructors().get(0), rec.canonicalConstructor());

rec = index.getClassByName("test.RecordWithCustomCanonicalCtor");
assertEquals(1, rec.constructors().size());
assertEquals(rec.constructors().get(0), rec.canonicalConstructor());

rec = index.getClassByName("test.RecordWithMultipleCtorsAndDefaultCanonicalCtor");
assertEquals(4, rec.constructors().size());
assertEquals(2, rec.canonicalConstructor().parametersCount());
assertEquals(PrimitiveType.INT, rec.canonicalConstructor().parameterType(0));
assertEquals(ClassType.create(String.class), rec.canonicalConstructor().parameterType(1));

rec = index.getClassByName("test.RecordWithMultipleCtorsAndCompactCanonicalCtor");
assertEquals(4, rec.constructors().size());
assertEquals(2, rec.canonicalConstructor().parametersCount());
assertEquals(PrimitiveType.INT, rec.canonicalConstructor().parameterType(0));
assertEquals(ClassType.create(String.class), rec.canonicalConstructor().parameterType(1));

rec = index.getClassByName("test.RecordWithMultipleCtorsAndCustomCanonicalCtor");
assertEquals(4, rec.constructors().size());
assertEquals(2, rec.canonicalConstructor().parametersCount());
assertEquals(PrimitiveType.INT, rec.canonicalConstructor().parameterType(0));
assertEquals(ClassType.create(String.class), rec.canonicalConstructor().parameterType(1));

assertNull(index.getClassByName(RecordTestCase.class).canonicalConstructor());
}

private Index buildIndex() throws IOException {
Indexer indexer = new Indexer();
indexer.index(getClass().getClassLoader().getResourceAsStream("test/RecordExample.class"));
Expand All @@ -160,6 +209,17 @@ private Index buildIndex() throws IOException {
indexer.index(getClass().getClassLoader().getResourceAsStream("test/RecordExample$ComponentAnnotation.class"));
indexer.index(getClass().getClassLoader().getResourceAsStream("test/RecordExample$FieldAnnotation.class"));
indexer.index(getClass().getClassLoader().getResourceAsStream("test/RecordExample$AccessorAnnotation.class"));
indexer.index(getClass().getClassLoader().getResourceAsStream("test/RecordWithCompactCanonicalCtor.class"));
indexer.index(getClass().getClassLoader().getResourceAsStream("test/RecordWithCustomCanonicalCtor.class"));
indexer.index(getClass().getClassLoader().getResourceAsStream("test/RecordWithDefaultCanonicalCtor.class"));
indexer.index(getClass().getClassLoader().getResourceAsStream("test/RecordWithMultipleCtorsAndCompactCanonicalCtor.class"));
indexer.index(getClass().getClassLoader().getResourceAsStream("test/RecordWithMultipleCtorsAndCustomCanonicalCtor.class"));
indexer.index(getClass().getClassLoader().getResourceAsStream("test/RecordWithMultipleCtorsAndDefaultCanonicalCtor.class"));
indexer.index(getClass().getClassLoader().getResourceAsStream("test/RecordWithNoComponentsAndCompactCanonicalCtor.class"));
indexer.index(getClass().getClassLoader().getResourceAsStream("test/RecordWithNoComponentsAndCustomCanonicalCtor.class"));
indexer.index(getClass().getClassLoader().getResourceAsStream("test/RecordWithNoComponentsAndDefaultCanonicalCtor.class"));

indexer.indexClass(RecordTestCase.class);

Index index = indexer.complete();
return IndexingUtil.roundtrip(index);
Expand Down
12 changes: 12 additions & 0 deletions test-data/src/main/java/test/RecordWithCompactCanonicalCtor.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package test;

public record RecordWithCompactCanonicalCtor(int foo, String bar) {
public RecordWithCompactCanonicalCtor {
if (foo < 0) {
throw new IllegalArgumentException();
}
if (bar == null) {
throw new IllegalArgumentException();
}
}
}
15 changes: 15 additions & 0 deletions test-data/src/main/java/test/RecordWithCustomCanonicalCtor.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package test;

public record RecordWithCustomCanonicalCtor(int foo, String bar) {
public RecordWithCustomCanonicalCtor(int foo, String bar) {
if (foo < 0) {
throw new IllegalArgumentException();
}
if (bar == null) {
throw new IllegalArgumentException();
}

this.foo = foo;
this.bar = bar;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package test;

public record RecordWithDefaultCanonicalCtor(int foo, String bar) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package test;

public record RecordWithMultipleCtorsAndCompactCanonicalCtor(int foo, String bar) {
public RecordWithMultipleCtorsAndCompactCanonicalCtor {
if (foo < 0) {
throw new IllegalArgumentException();
}
if (bar == null) {
throw new IllegalArgumentException();
}
}

public RecordWithMultipleCtorsAndCompactCanonicalCtor(int foo) {
this(foo, "");
}

public RecordWithMultipleCtorsAndCompactCanonicalCtor(String bar) {
this(0, bar);
}

public RecordWithMultipleCtorsAndCompactCanonicalCtor(String bar, int foo) {
this(foo, bar);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package test;

public record RecordWithMultipleCtorsAndCustomCanonicalCtor(int foo, String bar) {
public RecordWithMultipleCtorsAndCustomCanonicalCtor(int foo, String bar) {
if (foo < 0) {
throw new IllegalArgumentException();
}
if (bar == null) {
throw new IllegalArgumentException();
}

this.foo = foo;
this.bar = bar;
}

public RecordWithMultipleCtorsAndCustomCanonicalCtor(int foo) {
this(foo, "");
}

public RecordWithMultipleCtorsAndCustomCanonicalCtor(String bar) {
this(0, bar);
}

public RecordWithMultipleCtorsAndCustomCanonicalCtor(String bar, int foo) {
this(foo, bar);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package test;

public record RecordWithMultipleCtorsAndDefaultCanonicalCtor(int foo, String bar) {
RecordWithMultipleCtorsAndDefaultCanonicalCtor(int foo) {
this(foo, "");
}

public RecordWithMultipleCtorsAndDefaultCanonicalCtor(String bar) {
this(0, bar);
}

public RecordWithMultipleCtorsAndDefaultCanonicalCtor(String bar, int foo) {
this(foo, bar);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package test;

public record RecordWithNoComponentsAndCompactCanonicalCtor() {
public RecordWithNoComponentsAndCompactCanonicalCtor {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package test;

public record RecordWithNoComponentsAndCustomCanonicalCtor() {
public RecordWithNoComponentsAndCustomCanonicalCtor() {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package test;

public record RecordWithNoComponentsAndDefaultCanonicalCtor() {
}

0 comments on commit 6b0f3e3

Please sign in to comment.