Skip to content

Commit db3a706

Browse files
committed
Added support for java records
1 parent 41de14d commit db3a706

4 files changed

Lines changed: 78 additions & 47 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,4 @@ hs_err_pid*
2727
/build/
2828
gradle.properties
2929
/bin/
30+
.idea

build.gradle

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,21 @@ plugins {
33
id 'maven-publish'
44
id 'signing'
55
id 'checkstyle'
6-
id 'com.diffplug.spotless' version '6.17.0'
7-
id 'com.github.spotbugs' version '5.0.14'
8-
id 'com.github.ben-manes.versions' version '0.46.0'
6+
id 'com.diffplug.spotless' version '7.0.4'
7+
id 'com.github.spotbugs' version '6.1.13'
8+
id 'com.github.ben-manes.versions' version '0.52.0'
99
}
1010

1111
group 'com.formkiq'
12-
version '1.4.2'
12+
version '1.5.0'
1313

1414
dependencies {
15-
annotationProcessor group: 'com.google.auto.service', name: 'auto-service', version: '1.0.1'
16-
compileOnly group: 'com.google.auto.service', name: 'auto-service', version: '1.0.1'
17-
compileOnly group: 'com.google.auto.service', name: 'auto-service-annotations', version: '1.0.1'
15+
annotationProcessor group: 'com.google.auto.service', name: 'auto-service', version: '1.1.1'
16+
compileOnly group: 'com.google.auto.service', name: 'auto-service', version: '1.1.1'
17+
compileOnly group: 'com.google.auto.service', name: 'auto-service-annotations', version: '1.1.1'
1818

1919
implementation group: 'com.formkiq', name: 'graalvm-annotations', version: '1.2.0'
20-
implementation group: 'com.google.code.gson', name: 'gson', version: '2.10.1'
20+
implementation group: 'com.google.code.gson', name: 'gson', version: '2.13.1'
2121
testImplementation group: 'junit', name: 'junit', version:'4.+'
2222
testImplementation group: 'com.google.testing.compile', name: 'compile-testing', version: '0.21.0'
2323
}
@@ -66,7 +66,7 @@ java {
6666
withSourcesJar()
6767

6868
toolchain {
69-
languageVersion.set(JavaLanguageVersion.of(11))
69+
languageVersion.set(JavaLanguageVersion.of(17))
7070
}
7171
}
7272

src/main/java/com/formkiq/graalvm/processors/GraalvmReflectAnnontationProcessor.java

Lines changed: 26 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import java.lang.reflect.Field;
2929
import java.lang.reflect.Method;
3030
import java.net.URL;
31+
import java.nio.charset.StandardCharsets;
3132
import java.nio.file.Files;
3233
import java.util.ArrayList;
3334
import java.util.Arrays;
@@ -78,9 +79,9 @@ public class GraalvmReflectAnnontationProcessor extends AbstractProcessor {
7879
/** The package separator character: '.'. */
7980
private static final char PACKAGE_SEPARATOR = '.';
8081
/** {@link Gson}. */
81-
private Gson gson = new GsonBuilder().disableHtmlEscaping().create();
82+
private final Gson gson = new GsonBuilder().disableHtmlEscaping().create();
8283
/** {@link List} of {@link Reflect}. */
83-
private Map<String, Reflect> reflects = new HashMap<>();
84+
private final Map<String, Reflect> reflects = new HashMap<>();
8485

8586
private TypeElement asTypeElement(final TypeMirror typeMirror) {
8687
Types typeUtils = this.processingEnv.getTypeUtils();
@@ -117,7 +118,7 @@ private List<String> findClasses(final Element element, final String key) {
117118
List<? extends AnnotationValue> typeMirrors = (List<? extends AnnotationValue>) value;
118119

119120
for (AnnotationValue val : typeMirrors) {
120-
String clazz = ((TypeMirror) val.getValue()).toString();
121+
String clazz = val.getValue().toString();
121122

122123
LOGGER.log(LOGLEVEL, "processing ImportedClass " + clazz);
123124
processImportedClass(clazz);
@@ -160,7 +161,7 @@ String generateReflectConfigPath(final Set<String> keys) {
160161

161162
Set<String> strings =
162163
keys.stream()
163-
.map(m -> removePartsContainingDotFollowedByCapital(m))
164+
.map(this::removePartsContainingDotFollowedByCapital)
164165
.filter(m -> m != null && m.length() > 1)
165166
.collect(Collectors.toSet());
166167

@@ -173,7 +174,7 @@ String generateReflectConfigPath(final Set<String> keys) {
173174
strings.stream()
174175
.filter(s -> s.length() == shortestLength)
175176
.sorted()
176-
.collect(Collectors.toList());
177+
.toList();
177178

178179
return list.get(0);
179180
}
@@ -194,6 +195,7 @@ private String getClassNameByType(final Element element) {
194195
className = ((TypeElement) element.getEnclosingElement()).getQualifiedName().toString();
195196
break;
196197
case ENUM:
198+
case RECORD:
197199
case CLASS:
198200
TypeElement te = (TypeElement) element;
199201

@@ -211,7 +213,7 @@ private String getClassNameByType(final Element element) {
211213

212214
int pos = e.indexOf(simpleNames.get(0));
213215
if (pos > 0) {
214-
className = e.substring(0, pos) + simpleNames.stream().collect(Collectors.joining("$"));
216+
className = e.substring(0, pos) + String.join("$", simpleNames);
215217
}
216218
}
217219

@@ -275,12 +277,12 @@ private Reflect processClass(final Reflect reflect, final Reflectable reflectabl
275277

276278
LOGGER.log(LOGLEVEL, "processClass " + reflect.name());
277279
reflect
278-
.allDeclaredConstructors(Boolean.valueOf(reflectable.allDeclaredConstructors()))
279-
.allDeclaredFields(Boolean.valueOf(reflectable.allDeclaredFields()))
280-
.allDeclaredMethods(Boolean.valueOf(reflectable.allDeclaredMethods()))
281-
.allPublicConstructors(Boolean.valueOf(reflectable.allPublicConstructors()))
282-
.allPublicFields(Boolean.valueOf(reflectable.allPublicFields()))
283-
.allPublicMethods(Boolean.valueOf(reflectable.allPublicMethods()));
280+
.allDeclaredConstructors(reflectable.allDeclaredConstructors())
281+
.allDeclaredFields(reflectable.allDeclaredFields())
282+
.allDeclaredMethods(reflectable.allDeclaredMethods())
283+
.allPublicConstructors(reflectable.allPublicConstructors())
284+
.allPublicFields(reflectable.allPublicFields())
285+
.allPublicMethods(reflectable.allPublicMethods());
284286

285287
return reflect;
286288
}
@@ -296,12 +298,12 @@ private Reflect processClass(final Reflect reflect, final ReflectableClass refle
296298

297299
LOGGER.log(LOGLEVEL, "processClass " + reflect.name());
298300
reflect
299-
.allDeclaredConstructors(Boolean.valueOf(reflectable.allDeclaredConstructors()))
300-
.allDeclaredFields(Boolean.valueOf(reflectable.allDeclaredFields()))
301-
.allDeclaredMethods(Boolean.valueOf(reflectable.allDeclaredMethods()))
302-
.allPublicConstructors(Boolean.valueOf(reflectable.allPublicConstructors()))
303-
.allPublicFields(Boolean.valueOf(reflectable.allPublicFields()))
304-
.allPublicMethods(Boolean.valueOf(reflectable.allPublicMethods()));
301+
.allDeclaredConstructors(reflectable.allDeclaredConstructors())
302+
.allDeclaredFields(reflectable.allDeclaredFields())
303+
.allDeclaredMethods(reflectable.allDeclaredMethods())
304+
.allPublicConstructors(reflectable.allPublicConstructors())
305+
.allPublicFields(reflectable.allPublicFields())
306+
.allPublicMethods(reflectable.allPublicMethods());
305307

306308
return reflect;
307309
}
@@ -333,7 +335,7 @@ private void processImportedClass(final String clazz) {
333335
Reflectable reflection = method.getAnnotation(Reflectable.class);
334336
if (reflection != null) {
335337
List<String> parameterTypes =
336-
Arrays.asList(method.getParameters()).stream()
338+
Arrays.stream(method.getParameters())
337339
.map(p -> p.getParameterizedType().getTypeName())
338340
.collect(Collectors.toList());
339341

@@ -374,7 +376,7 @@ private void processImportFiles(final Element element) {
374376

375377
for (String file : reflectImport.files()) {
376378

377-
if (file.length() > 0) {
379+
if (!file.isEmpty()) {
378380
try {
379381

380382
ClassLoader classLoader = getClass().getClassLoader();
@@ -431,14 +433,14 @@ private void processingReflectable(final RoundEnvironment roundEnv) {
431433

432434
LOGGER.log(LOGLEVEL, "adding Method " + methodName + " to " + className);
433435
reflect.addMethod(methodName, parameterTypes);
434-
435436
break;
436437
case ENUM:
438+
case RECORD:
437439
case CLASS:
438440
reflect = processClass(reflect, reflectable);
439441
break;
440442
default:
441-
break;
443+
throw new RuntimeException("Unsupported kind of element: " + element.getKind());
442444
}
443445
}
444446
}
@@ -555,9 +557,9 @@ private void writeOutput() {
555557
"META-INF/native-image/" + name + "/reflect-config.json");
556558

557559
List<Map<String, Object>> data =
558-
this.reflects.values().stream().map(r -> r.data()).collect(Collectors.toList());
560+
this.reflects.values().stream().map(Reflect::data).collect(Collectors.toList());
559561

560-
try (Writer w = new OutputStreamWriter(file.openOutputStream(), "UTF-8")) {
562+
try (Writer w = new OutputStreamWriter(file.openOutputStream(), StandardCharsets.UTF_8)) {
561563
w.write(this.gson.toJson(data));
562564
}
563565

src/test/java/com/formkiq/graalvm/processors/GraalvmReflectAnnontationProcessorTest.java

Lines changed: 42 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
import com.google.testing.compile.Compilation;
2626
import com.google.testing.compile.JavaFileObjects;
2727
import java.io.IOException;
28-
import java.util.Collections;
2928
import java.util.Comparator;
3029
import java.util.List;
3130
import java.util.Map;
@@ -39,7 +38,7 @@
3938
public class GraalvmReflectAnnontationProcessorTest {
4039

4140
/** {@link Gson}. */
42-
private Gson gson = new GsonBuilder().disableHtmlEscaping().create();
41+
private final Gson gson = new GsonBuilder().disableHtmlEscaping().create();
4342

4443
/**
4544
* testReflectableImport01.
@@ -430,7 +429,7 @@ public void testInnerClassAnnotation01() throws IOException {
430429
assertEquals(Boolean.TRUE, map.get(i).get("allDeclaredMethods"));
431430
assertEquals(Boolean.TRUE, map.get(i).get("allDeclaredFields"));
432431
assertNull(map.get(i).get("fields"));
433-
assertNull(map.get(i++).get("methods"));
432+
assertNull(map.get(i).get("methods"));
434433
}
435434

436435
/**
@@ -466,7 +465,7 @@ public void testInnerClassAnnotation02() throws IOException {
466465
int i = 0;
467466
assertEquals("test.Test6", map.get(i++).get("name"));
468467
assertEquals("test.Test6$Data0", map.get(i++).get("name"));
469-
assertEquals("test.Test6$Data0$Data1", map.get(i++).get("name"));
468+
assertEquals("test.Test6$Data0$Data1", map.get(i).get("name"));
470469
}
471470

472471
/**
@@ -506,10 +505,10 @@ public void testInnerClassAnnotation03() throws IOException {
506505
assertEquals("test.Test6", map.get(i++).get("name"));
507506
assertEquals("test.Test6$Data0", map.get(i++).get("name"));
508507
assertEquals("test.Test6$Data0$Data1", map.get(i++).get("name"));
509-
assertEquals("test.Test6$Data0$Data1$Data2", map.get(i++).get("name"));
508+
assertEquals("test.Test6$Data0$Data1$Data2", map.get(i).get("name"));
510509
}
511510

512-
@SuppressWarnings({"unchecked", "resource"})
511+
@SuppressWarnings({"unchecked"})
513512
private List<Map<String, Object>> getReflectConf(
514513
final Compilation compilation, final String filename)
515514
throws JsonSyntaxException, JsonIOException, IOException {
@@ -518,16 +517,10 @@ private List<Map<String, Object>> getReflectConf(
518517
StandardLocation.CLASS_OUTPUT,
519518
"META-INF/native-image/" + filename + "/reflect-config.json");
520519

520+
assertTrue(file.isPresent());
521521
List<Map<String, Object>> list = this.gson.fromJson(file.get().openReader(false), List.class);
522522

523-
Collections.sort(
524-
list,
525-
new Comparator<Map<String, Object>>() {
526-
@Override
527-
public int compare(final Map<String, Object> o1, final Map<String, Object> o2) {
528-
return o1.get("name").toString().compareTo(o2.get("name").toString());
529-
}
530-
});
523+
list.sort(Comparator.comparing(o -> o.get("name").toString()));
531524

532525
return list;
533526
}
@@ -880,6 +873,41 @@ public void testEnumAnnotations() throws IOException {
880873
assertEquals(Boolean.TRUE, map.get(0).get("allDeclaredFields"));
881874
}
882875

876+
/**
877+
* test java record.
878+
*
879+
* @throws IOException IOException
880+
*/
881+
@Test
882+
public void testRecordAnnotations() throws IOException {
883+
JavaFileObject recordSource = JavaFileObjects.forSourceString(
884+
"com.example.TestRecord",
885+
"""
886+
package com.example;
887+
888+
import com.formkiq.graalvm.annotations.Reflectable;
889+
890+
@Reflectable
891+
public record TestRecord(String name) {}
892+
"""
893+
);
894+
Compilation compilation =
895+
javac()
896+
.withProcessors(new GraalvmReflectAnnontationProcessor())
897+
.compile(recordSource);
898+
899+
List<Map<String, Object>> map = getReflectConf(compilation, "com.example");
900+
901+
assertEquals(1, map.size());
902+
assertEquals("com.example.TestRecord", map.get(0).get("name"));
903+
assertEquals(Boolean.TRUE, map.get(0).get("allPublicConstructors"));
904+
assertEquals(Boolean.TRUE, map.get(0).get("allPublicMethods"));
905+
assertEquals(Boolean.TRUE, map.get(0).get("allPublicFields"));
906+
assertEquals(Boolean.FALSE, map.get(0).get("allDeclaredConstructors"));
907+
assertEquals(Boolean.TRUE, map.get(0).get("allDeclaredMethods"));
908+
assertEquals(Boolean.TRUE, map.get(0).get("allDeclaredFields"));
909+
}
910+
883911
/** Test Reflect Config Path. */
884912
@Test
885913
public void testGenerateReflectConfigPath01() {

0 commit comments

Comments
 (0)