Skip to content

Commit

Permalink
[json-core] SimpleMapper add type support for customer JsonAdapters (#…
Browse files Browse the repository at this point in the history
…310)

For cases where we want to manually build a JsonAdapter and then use that via SimpleMapper
  • Loading branch information
rbygrave authored Dec 12, 2024
1 parent 7436f02 commit bcf44c4
Show file tree
Hide file tree
Showing 4 changed files with 154 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.avaje.json.simple;

import io.avaje.json.JsonAdapter;
import io.avaje.json.core.CoreTypes;
import io.avaje.json.stream.JsonStream;

Expand All @@ -8,16 +9,23 @@

final class DSimpleMapper implements SimpleMapper {

private final JsonStream jsonStream;
private final Type<Object> objectType;
private final Type<Map<String,Object>> mapType;
private final Type<List<Object>> listType;

DSimpleMapper(JsonStream jsonStream, CoreTypes.CoreAdapters adapters) {
this.jsonStream = jsonStream;
this.objectType = new DTypeMapper<>(adapters.objectAdapter(), jsonStream);
this.mapType = new DTypeMapper<>(adapters.mapAdapter(), jsonStream);
this.listType = new DTypeMapper<>(adapters.listAdapter(), jsonStream);
}

@Override
public <T> Type<T> type(JsonAdapter<T> myAdapter) {
return new DTypeMapper<>(myAdapter, jsonStream);
}

@Override
public Type<Object> object() {
return objectType;
Expand Down
10 changes: 10 additions & 0 deletions json-core/src/main/java/io/avaje/json/simple/SimpleMapper.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.avaje.json.simple;

import io.avaje.json.JsonAdapter;
import io.avaje.json.JsonReader;
import io.avaje.json.JsonWriter;
import io.avaje.json.stream.JsonStream;
Expand Down Expand Up @@ -56,6 +57,15 @@ static Builder builder() {
*/
Type<List<Object>> list();

/**
* Return a Type specific mapper for the given JsonAdapter.
*
* @param customAdapter The custom adapter to use.
* @param <T> The type of the class to map to/from json.
* @return The Type specific mapper.
*/
<T> Type<T> type(JsonAdapter<T> customAdapter);

/**
* Write the object to JSON string.
* <p>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package io.avaje.json.simple;

import io.avaje.json.JsonAdapter;
import io.avaje.json.JsonReader;
import io.avaje.json.JsonWriter;
import org.junit.jupiter.api.Test;

import static org.assertj.core.api.Assertions.assertThat;

class CustomAdapter2Test {

static final SimpleMapper simpleMapper = SimpleMapper.builder().build();

@Test
void mapUsingCustomAdapter() {

MyAdapterUsingRaw myAdapter = new MyAdapterUsingRaw();

SimpleMapper.Type<MyOtherType> type = simpleMapper.type(myAdapter);

MyOtherType source = new MyOtherType();
source.foo = "hi";
source.bar = 42;
String asJson = type.toJson(source);

MyOtherType fromJson = type.fromJson(asJson);

assertThat(fromJson.foo).isEqualTo(source.foo);
assertThat(fromJson.bar).isEqualTo(source.bar);
}

static class MyOtherType {
String foo;
int bar;
}

static class MyAdapterUsingRaw implements JsonAdapter<MyOtherType> {

@Override
public void toJson(JsonWriter writer, MyOtherType value) {
writer.beginObject();
writer.name("foo");
writer.value(value.foo);
writer.name("bar");
writer.value(value.bar);
writer.endObject();
}

@Override
public MyOtherType fromJson(JsonReader reader) {
MyOtherType result = new MyOtherType();

reader.beginObject();

String key;
while (reader.hasNextField()) {
key = reader.nextField();
switch (key) {
case "foo":
result.foo = reader.readString();
break;
case "bar":
result.bar = reader.readInt();
break;
default:
reader.skipValue();
}
}
reader.endObject();
return result;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package io.avaje.json.simple;

import io.avaje.json.JsonAdapter;
import io.avaje.json.JsonReader;
import io.avaje.json.JsonWriter;
import org.junit.jupiter.api.Test;

import java.util.Map;

import static org.assertj.core.api.Assertions.assertThat;

class CustomAdapterTest {

static final SimpleMapper simpleMapper = SimpleMapper.builder().build();

@Test
void mapUsingCustomAdapter() {

MyAdapter myAdapter = new MyAdapter(simpleMapper);

SimpleMapper.Type<MyCustomType> type = simpleMapper.type(myAdapter);

MyCustomType source = new MyCustomType();
source.foo = "hi";
source.bar = 42;
String asJson = type.toJson(source);

MyCustomType fromJson = type.fromJson(asJson);

assertThat(fromJson.foo).isEqualTo(source.foo);
assertThat(fromJson.bar).isEqualTo(source.bar);
}

static class MyCustomType {
public String foo;
public int bar;
}

static class MyAdapter implements JsonAdapter<MyCustomType> {

private final SimpleMapper.Type<Map<String, Object>> map;

public MyAdapter(SimpleMapper simpleMapper) {
this.map = simpleMapper.map();
}

@Override
public void toJson(JsonWriter writer, MyCustomType value) {
Map<String, Object> foo = Map.of("foo", value.foo, "bar", value.bar);
map.toJson(foo, writer);
}

@Override
public MyCustomType fromJson(JsonReader reader) {
Map<String, Object> mapValue = map.fromJson(reader);
MyCustomType myCustomType = new MyCustomType();
myCustomType.foo = (String)mapValue.get("foo");
Number bar = (Number)mapValue.get("bar");
myCustomType.bar = bar == null ? 0 : bar.intValue();
return myCustomType;
}
}
}

0 comments on commit bcf44c4

Please sign in to comment.