Skip to content

Commit 8757a1d

Browse files
Copilotozlerhakan
andcommitted
Restore Java 11 compatibility while maintaining record support for Java 17+
Co-authored-by: ozlerhakan <[email protected]>
1 parent 7b00c71 commit 8757a1d

File tree

4 files changed

+106
-15
lines changed

4 files changed

+106
-15
lines changed

.github/workflows/maven.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ jobs:
44
test:
55
strategy:
66
matrix:
7-
java: [ 17, 23 ]
7+
java: [ 11, 17, 23 ]
88
runs-on: ubuntu-latest
99
steps:
1010
- uses: actions/checkout@v3

README.adoc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,8 @@ PoijiOptions options = PoijiOptionsBuilder.settings()
207207

208208
Starting with version 4.9.0, Poiji supports Java Records (Java 16+). Records provide a concise way to declare data carrier classes with immutable fields.
209209

210+
**Compatibility Note**: The library maintains Java 11 compatibility for regular classes. Record support is automatically available when running on Java 17+ runtime, but the library will work on Java 11 for traditional POJOs.
211+
210212
[source,java]
211213
----
212214
public record EmployeeRecord(
@@ -254,6 +256,12 @@ Records work with all annotations including:
254256

255257
Records work with both XLS and XLSX formats and support all standard Poiji options.
256258

259+
**Requirements**:
260+
261+
* Library compiled with Java 11 (maintains backward compatibility)
262+
* Record support requires Java 17+ runtime
263+
* Traditional POJOs work on any Java 11+ runtime
264+
257265
=== Prefer Default Value
258266

259267
If you want a date field to return `null` rather than a default date, use `PoijiOptionsBuilder` with the `preferNullOverDefault` method as follows:

pom.xml

Lines changed: 64 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,9 @@
5252

5353
<maven-release-plugin.version>3.0.1</maven-release-plugin.version>
5454
<maven-enforcer-plugin.version>3.4.1</maven-enforcer-plugin.version>
55-
<maven.compiler.source>17</maven.compiler.source>
56-
<maven.compiler.target>17</maven.compiler.target>
57-
<java.version>17</java.version>
55+
<maven.compiler.source>11</maven.compiler.source>
56+
<maven.compiler.target>11</maven.compiler.target>
57+
<java.version>11</java.version>
5858
</properties>
5959

6060
<dependencies>
@@ -96,7 +96,7 @@
9696
<artifactId>maven-compiler-plugin</artifactId>
9797
<version>3.13.0</version>
9898
<configuration>
99-
<release>17</release>
99+
<release>11</release>
100100
</configuration>
101101
</plugin>
102102
<plugin>
@@ -184,6 +184,66 @@
184184
<javadoc.none>-Xdoclint:none</javadoc.none>
185185
</properties>
186186
</profile>
187+
<profile>
188+
<id>java17-tests</id>
189+
<activation>
190+
<jdk>[17,)</jdk>
191+
</activation>
192+
<build>
193+
<plugins>
194+
<plugin>
195+
<groupId>org.apache.maven.plugins</groupId>
196+
<artifactId>maven-compiler-plugin</artifactId>
197+
<version>3.13.0</version>
198+
<executions>
199+
<execution>
200+
<id>default-testCompile</id>
201+
<phase>test-compile</phase>
202+
<goals>
203+
<goal>testCompile</goal>
204+
</goals>
205+
<configuration>
206+
<release>17</release>
207+
</configuration>
208+
</execution>
209+
</executions>
210+
</plugin>
211+
</plugins>
212+
</build>
213+
</profile>
214+
<profile>
215+
<id>java11-tests</id>
216+
<activation>
217+
<jdk>(,17)</jdk>
218+
</activation>
219+
<build>
220+
<plugins>
221+
<plugin>
222+
<groupId>org.apache.maven.plugins</groupId>
223+
<artifactId>maven-compiler-plugin</artifactId>
224+
<version>3.13.0</version>
225+
<executions>
226+
<execution>
227+
<id>default-testCompile</id>
228+
<phase>test-compile</phase>
229+
<goals>
230+
<goal>testCompile</goal>
231+
</goals>
232+
<configuration>
233+
<release>11</release>
234+
<testExcludes>
235+
<exclude>**/model/byid/CalculationRecord.java</exclude>
236+
<exclude>**/model/byname/EmployeeRecord.java</exclude>
237+
<exclude>**/model/byname/PersonRecord.java</exclude>
238+
<exclude>**/RecordDeserializationTest.java</exclude>
239+
</testExcludes>
240+
</configuration>
241+
</execution>
242+
</executions>
243+
</plugin>
244+
</plugins>
245+
</build>
246+
</profile>
187247
<profile>
188248
<id>coverage</id>
189249
<build>

src/main/java/com/poiji/util/ReflectUtil.java

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import java.lang.annotation.Annotation;
99
import java.lang.reflect.Constructor;
1010
import java.lang.reflect.Field;
11-
import java.lang.reflect.RecordComponent;
11+
import java.lang.reflect.Method;
1212
import java.util.ArrayList;
1313
import java.util.Collection;
1414
import java.util.List;
@@ -36,31 +36,43 @@ public static <T> T newInstanceOf(Class<T> type) {
3636

3737
/**
3838
* Creates an instance of a record class using its canonical constructor with provided values.
39+
* This method uses reflection to maintain compatibility with Java 11 while supporting records on Java 17+.
3940
*
4041
* @param <T> the type of the record
4142
* @param type the record class
4243
* @param recordValues a map of field names to their values
4344
* @return a new instance of the record
4445
*/
4546
public static <T> T newRecordInstance(Class<T> type, Map<String, Object> recordValues) {
46-
if (!type.isRecord()) {
47+
if (!isRecord(type)) {
4748
throw new PoijiInstantiationException("Type " + type.getName() + " is not a record",
4849
new IllegalArgumentException("Expected a record type"));
4950
}
5051

5152
try {
52-
RecordComponent[] components = type.getRecordComponents();
53+
// Use reflection to call getRecordComponents() to maintain Java 11 compatibility
54+
Method getRecordComponentsMethod = Class.class.getMethod("getRecordComponents");
55+
Object[] components = (Object[]) getRecordComponentsMethod.invoke(type);
56+
5357
Class<?>[] parameterTypes = new Class<?>[components.length];
5458
Object[] args = new Object[components.length];
5559

60+
// Get methods from RecordComponent class using reflection
61+
Class<?> recordComponentClass = Class.forName("java.lang.reflect.RecordComponent");
62+
Method getNameMethod = recordComponentClass.getMethod("getName");
63+
Method getTypeMethod = recordComponentClass.getMethod("getType");
64+
5665
for (int i = 0; i < components.length; i++) {
57-
RecordComponent component = components[i];
58-
parameterTypes[i] = component.getType();
59-
Object value = recordValues.get(component.getName());
66+
Object component = components[i];
67+
String componentName = (String) getNameMethod.invoke(component);
68+
Class<?> componentType = (Class<?>) getTypeMethod.invoke(component);
69+
70+
parameterTypes[i] = componentType;
71+
Object value = recordValues.get(componentName);
6072

6173
// If value is null, use default values for primitives
62-
if (value == null && component.getType().isPrimitive()) {
63-
value = getDefaultValue(component.getType());
74+
if (value == null && componentType.isPrimitive()) {
75+
value = getDefaultValue(componentType);
6476
}
6577

6678
args[i] = value;
@@ -101,13 +113,24 @@ private static Object getDefaultValue(Class<?> type) {
101113
}
102114

103115
/**
104-
* Checks if a class is a record.
116+
* Checks if a class is a record using reflection to maintain Java 11 compatibility.
117+
* Records are only available in Java 16+, so this method will return false on earlier versions.
105118
*
106119
* @param type the class to check
107120
* @return true if the class is a record, false otherwise
108121
*/
109122
public static boolean isRecord(Class<?> type) {
110-
return type.isRecord();
123+
try {
124+
// Use reflection to call isRecord() method to maintain Java 11 compatibility
125+
Method isRecordMethod = Class.class.getMethod("isRecord");
126+
return (Boolean) isRecordMethod.invoke(type);
127+
} catch (NoSuchMethodException e) {
128+
// isRecord() method doesn't exist, we're running on Java < 16
129+
return false;
130+
} catch (Exception e) {
131+
// Some other error occurred
132+
return false;
133+
}
111134
}
112135

113136
/**

0 commit comments

Comments
 (0)