Skip to content

Commit 74bd297

Browse files
authored
Fix custom type adapters with private fields (#382)
1 parent 7df399b commit 74bd297

File tree

7 files changed

+189
-9
lines changed

7 files changed

+189
-9
lines changed
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package org.example.other.custom;
2+
3+
import java.util.List;
4+
5+
import io.avaje.jsonb.Json;
6+
7+
@Json
8+
public class Example {
9+
private int code;
10+
private WrapMap map;
11+
private List<WrapMap2> map2;
12+
13+
public int getCode() {
14+
return code;
15+
}
16+
17+
public void setCode(int code) {
18+
this.code = code;
19+
}
20+
21+
public WrapMap getMap() {
22+
return map;
23+
}
24+
25+
public void setMap(WrapMap map) {
26+
this.map = map;
27+
}
28+
29+
public List<WrapMap2> getMap2() {
30+
return map2;
31+
}
32+
33+
public void setMap2(List<WrapMap2> map2) {
34+
this.map2 = map2;
35+
}
36+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package org.example.other.custom;
2+
3+
import java.util.AbstractMap;
4+
import java.util.Map;
5+
import java.util.Set;
6+
7+
public class WrapMap extends AbstractMap<String, String> {
8+
private final Map<String, String> delegate;
9+
10+
public WrapMap(Map<String, String> map) {
11+
delegate = map;
12+
}
13+
14+
@Override
15+
public Set<Entry<String, String>> entrySet() {
16+
return delegate.entrySet();
17+
}
18+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package org.example.other.custom;
2+
3+
import java.util.AbstractMap;
4+
import java.util.Map;
5+
import java.util.Set;
6+
7+
public class WrapMap2 extends AbstractMap<String, String> {
8+
private final Map<String, String> delegate;
9+
10+
public WrapMap2(Map<String, String> map) {
11+
delegate = map;
12+
}
13+
14+
@Override
15+
public Set<Entry<String, String>> entrySet() {
16+
return delegate.entrySet();
17+
}
18+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package org.example.other.custom;
2+
3+
import java.util.Map;
4+
5+
import io.avaje.json.JsonAdapter;
6+
import io.avaje.json.JsonReader;
7+
import io.avaje.json.JsonWriter;
8+
import io.avaje.jsonb.CustomAdapter;
9+
import io.avaje.jsonb.Jsonb;
10+
import io.avaje.jsonb.Types;
11+
12+
@CustomAdapter
13+
public class WrapMap2JsonAdapter implements JsonAdapter<WrapMap2> {
14+
private final JsonAdapter<Map<String, String>> stringMapJsonAdapter;
15+
16+
public WrapMap2JsonAdapter(Jsonb jsonb) {
17+
this.stringMapJsonAdapter =
18+
jsonb.adapter(Types.newParameterizedType(Map.class, String.class, String.class));
19+
}
20+
21+
@Override
22+
public WrapMap2 fromJson(JsonReader reader) {
23+
return new WrapMap2(stringMapJsonAdapter.fromJson(reader));
24+
}
25+
26+
@Override
27+
public void toJson(JsonWriter writer, WrapMap2 wrapMap) {
28+
writer.beginObject();
29+
wrapMap.forEach(
30+
(key, value) -> {
31+
writer.name(key);
32+
writer.value(value);
33+
});
34+
writer.endObject();
35+
}
36+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package org.example.other.custom;
2+
3+
import java.util.Map;
4+
5+
import io.avaje.json.JsonAdapter;
6+
import io.avaje.json.JsonReader;
7+
import io.avaje.json.JsonWriter;
8+
import io.avaje.jsonb.CustomAdapter;
9+
import io.avaje.jsonb.Jsonb;
10+
import io.avaje.jsonb.Types;
11+
12+
@CustomAdapter
13+
public class WrapMapJsonAdapter implements JsonAdapter<WrapMap> {
14+
private final JsonAdapter<Map<String, String>> stringMapJsonAdapter;
15+
16+
public WrapMapJsonAdapter(Jsonb jsonb) {
17+
this.stringMapJsonAdapter =
18+
jsonb.adapter(Types.newParameterizedType(Map.class, String.class, String.class));
19+
}
20+
21+
@Override
22+
public WrapMap fromJson(JsonReader reader) {
23+
return new WrapMap(stringMapJsonAdapter.fromJson(reader));
24+
}
25+
26+
@Override
27+
public void toJson(JsonWriter writer, WrapMap wrapMap) {
28+
writer.beginObject();
29+
wrapMap.forEach(
30+
(key, value) -> {
31+
writer.name(key);
32+
writer.value(value);
33+
});
34+
writer.endObject();
35+
}
36+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package org.example.other.custom;
2+
3+
import io.avaje.jsonb.JsonType;
4+
import io.avaje.jsonb.Jsonb;
5+
import org.junit.jupiter.api.Test;
6+
7+
import java.util.List;
8+
import java.util.Map;
9+
10+
import static org.assertj.core.api.Assertions.assertThat;
11+
12+
class ExampleTest {
13+
14+
Jsonb jsonb = Jsonb.builder().build();
15+
JsonType<Example> jsonType = jsonb.type(Example.class);
16+
17+
@Test
18+
void toFromJson() {
19+
Example bean = new Example();
20+
bean.setCode(34);
21+
bean.setMap(new WrapMap(Map.of("a", "b")));
22+
bean.setMap2(List.of(new WrapMap2(Map.of("2a", "z")), new WrapMap2(Map.of("2b", "x"))));
23+
24+
final String asJson = jsonType.toJson(bean);
25+
assertThat(asJson).isEqualTo("{\"code\":34,\"map\":{\"a\":\"b\"},\"map2\":[{\"2a\":\"z\"},{\"2b\":\"x\"}]}");
26+
27+
final var fromJson = jsonType.fromJson(asJson);
28+
assertThat(fromJson.getCode()).isEqualTo(34);
29+
assertThat(fromJson.getMap()).containsEntry("a", "b");
30+
assertThat(fromJson.getMap2()).hasSize(2);
31+
assertThat(fromJson.getMap2().getFirst()).containsEntry("2a", "z");
32+
assertThat(fromJson.getMap2().getLast()).containsEntry("2b", "x");
33+
}
34+
}

jsonb-generator/src/main/java/io/avaje/jsonb/generator/JsonbProcessor.java

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,11 @@ private void registerCustomAdapters(Set<? extends Element> elements) {
161161
x -> {},
162162
() -> logNote(typeElement, "Non-Generic adapters should have a public constructor with a single Jsonb parameter"));
163163

164+
typeElement.getInterfaces().stream()
165+
.filter(t -> t.toString().contains("io.avaje.json.JsonAdapter"))
166+
.findFirst()
167+
.ifPresent(t -> sourceTypes.add(UType.parse(t).param0().fullWithoutAnnotations()));
168+
164169
meta.add(type);
165170
}
166171
}
@@ -229,7 +234,7 @@ private void cascadeTypes() {
229234
}
230235

231236
private void cascadeTypesInner() {
232-
final ArrayList<BeanReader> copy = new ArrayList<>(allReaders);
237+
final var copy = new ArrayList<>(allReaders);
233238
allReaders.clear();
234239

235240
final Set<String> extraTypes = new TreeSet<>();
@@ -239,22 +244,19 @@ private void cascadeTypesInner() {
239244
for (final String type : extraTypes) {
240245
if (!ignoreType(type)) {
241246
final TypeElement element = typeElement(type);
242-
if (element != null && cascadeElement(element)) {
247+
if (element != null && element.getKind() != ElementKind.ENUM) {
243248
writeAdapterForType(element);
244249
}
245250
}
246251
}
247252
}
248253

249-
private boolean cascadeElement(TypeElement element) {
250-
return element.getKind() != ElementKind.ENUM && !writtenTypes.contains(element.toString());
251-
}
252-
253254
private boolean ignoreType(String type) {
254255
return type.indexOf('.') == -1
255-
|| type.startsWith("java.")
256-
|| type.startsWith("javax.")
257-
|| sourceTypes.contains(type);
256+
|| type.startsWith("java.")
257+
|| type.startsWith("javax.")
258+
|| sourceTypes.contains(type)
259+
|| writtenTypes.contains(type);
258260
}
259261

260262
/**

0 commit comments

Comments
 (0)