-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add record deserialization support
- Loading branch information
1 parent
18cdbd4
commit 123a0f4
Showing
9 changed files
with
290 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
40 changes: 40 additions & 0 deletions
40
xjx-serdes/src/main/java/io/jonasg/xjx/serdes/deserialize/RecordWrapper.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
package io.jonasg.xjx.serdes.deserialize; | ||
|
||
import java.lang.reflect.Constructor; | ||
import java.lang.reflect.Field; | ||
import java.util.HashMap; | ||
import java.util.Map; | ||
|
||
public class RecordWrapper<T> { | ||
private final Map<String, Object> fieldMapping = new HashMap<>(); | ||
private final Class<T> type; | ||
|
||
public RecordWrapper(Class<T> type) { | ||
this.type = type; | ||
} | ||
|
||
public void set(String name, Object value) { | ||
this.fieldMapping.put(name, value); | ||
} | ||
|
||
public T record() { | ||
try { | ||
Constructor<?>[] constructors = type.getDeclaredConstructors(); | ||
|
||
Constructor<?> constructor = constructors[0]; | ||
constructor.setAccessible(true); | ||
|
||
Object[] args = new Object[constructor.getParameterCount()]; | ||
var parameters = constructor.getParameters(); | ||
for (int i = 0; i < parameters.length; i++) { | ||
String paramName = parameters[i].getName(); | ||
args[i] = fieldMapping.getOrDefault(paramName, null); | ||
} | ||
|
||
return (T) constructor.newInstance(args); | ||
|
||
} catch (Exception e) { | ||
throw new RuntimeException("Error creating record", e); | ||
} | ||
} | ||
} |
17 changes: 11 additions & 6 deletions
17
xjx-serdes/src/main/java/io/jonasg/xjx/serdes/deserialize/accessor/FieldAccessor.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
21 changes: 21 additions & 0 deletions
21
xjx-serdes/src/main/java/io/jonasg/xjx/serdes/deserialize/accessor/RecordFieldAccessor.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package io.jonasg.xjx.serdes.deserialize.accessor; | ||
|
||
import io.jonasg.xjx.serdes.deserialize.RecordWrapper; | ||
import io.jonasg.xjx.serdes.reflector.FieldReflector; | ||
|
||
public class RecordFieldAccessor implements FieldAccessor { | ||
|
||
private final FieldReflector field; | ||
|
||
private final RecordWrapper recordWrapper; | ||
|
||
public RecordFieldAccessor(FieldReflector field, RecordWrapper recordWrapper) { | ||
this.field = field; | ||
this.recordWrapper = recordWrapper; | ||
} | ||
|
||
@Override | ||
public void set(Object value) { | ||
recordWrapper.set(field.rawField().getName(), value); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
175 changes: 175 additions & 0 deletions
175
xjx-serdes/src/test/java/io/jonasg/xjx/serdes/deserialize/JavaRecordDeserializationTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,175 @@ | ||
package io.jonasg.xjx.serdes.deserialize; | ||
|
||
import static org.assertj.core.api.Assertions.assertThat; | ||
|
||
import org.junit.jupiter.api.Test; | ||
|
||
import io.jonasg.xjx.serdes.Tag; | ||
import io.jonasg.xjx.serdes.XjxSerdes; | ||
|
||
import java.util.List; | ||
|
||
public class JavaRecordDeserializationTest { | ||
|
||
@Test | ||
void deserializeTopLevelRecord() { | ||
// given | ||
record Person(@Tag(path = "/Person/name") String name) {} | ||
String data = """ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<Person> | ||
<name>John</name> | ||
</Person> | ||
"""; | ||
|
||
// when | ||
Person person = new XjxSerdes().read(data, Person.class); | ||
|
||
// then | ||
assertThat(person.name()).isEqualTo("John"); | ||
} | ||
|
||
@Test | ||
void recordAsField() { | ||
// given | ||
String data = """ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<House> | ||
<Person> | ||
<name>John</name> | ||
</Person> | ||
</House> | ||
"""; | ||
|
||
// when | ||
House house = new XjxSerdes().read(data, House.class); | ||
|
||
// then | ||
assertThat(house.person.name()).isEqualTo("John"); | ||
} | ||
|
||
@Test | ||
void relativeMappedFieldWithWithTopLevelMappedRootType() { | ||
// given | ||
@Tag(path = "/House") | ||
record Person(@Tag(path = "Person/name") String name) {} | ||
String data = """ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<House> | ||
<Person> | ||
<name>John</name> | ||
</Person> | ||
</House> | ||
"""; | ||
|
||
// when | ||
Person person = new XjxSerdes().read(data, Person.class); | ||
|
||
// then | ||
assertThat(person.name()).isEqualTo("John"); | ||
} | ||
|
||
|
||
@Test | ||
void absoluteMappedFieldWithWithTopLevelMappedRootType() { | ||
// given | ||
@Tag(path = "/House") | ||
record Person(@Tag(path = "/House/Person/name") String name) {} | ||
String data = """ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<House> | ||
<Person> | ||
<name>John</name> | ||
</Person> | ||
</House> | ||
"""; | ||
|
||
// when | ||
Person person = new XjxSerdes().read(data, Person.class); | ||
|
||
// then | ||
assertThat(person.name()).isEqualTo("John"); | ||
} | ||
|
||
@Test | ||
void recordWithComplexType() { | ||
// given | ||
String data = """ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<Computer> | ||
<Brand> | ||
<Name>Apple</Name> | ||
</Brand> | ||
</Computer> | ||
"""; | ||
|
||
// when | ||
Computer computer = new XjxSerdes().read(data, Computer.class); | ||
|
||
// then | ||
assertThat(computer.brand.name).isEqualTo("Apple"); | ||
} | ||
|
||
@Test | ||
void recordWithListType() { | ||
// given | ||
String data = """ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<Computers> | ||
<Brand> | ||
<Name>Apple</Name> | ||
</Brand> | ||
<Brand> | ||
<Name>Commodore</Name> | ||
</Brand> | ||
</Computers> | ||
"""; | ||
|
||
// when | ||
Computers computers = new XjxSerdes().read(data, Computers.class); | ||
|
||
// then | ||
assertThat(computers.brand).hasSize(2); | ||
} | ||
|
||
@Test | ||
void setFieldsToNullWhenNoMappingIsFound() { | ||
// given | ||
record Person(@Tag(path = "/Person/name") String name, String lastName) {} | ||
String data = """ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<Person> | ||
<name>John</name> | ||
</Person> | ||
"""; | ||
|
||
// when | ||
Person person = new XjxSerdes().read(data, Person.class); | ||
|
||
// then | ||
assertThat(person.lastName()).isNull(); | ||
} | ||
|
||
record Person(@Tag(path = "name") String name, String lastName) {} | ||
|
||
static class House { | ||
@Tag(path = "/House/Person") | ||
Person person; | ||
|
||
public House() { | ||
} | ||
} | ||
|
||
record Computer(@Tag(path = "/Computer/Brand") Brand brand) {} | ||
|
||
static class Brand { | ||
@Tag(path = "Name") | ||
String name; | ||
|
||
public Brand() { | ||
} | ||
} | ||
|
||
record Computers(@Tag(path = "/Computers", items = "Brand") List<Brand> brand) {} | ||
|
||
} |