Skip to content

Commit 0b2d706

Browse files
committed
Initial work on standard adapters
1 parent 545a80e commit 0b2d706

46 files changed

Lines changed: 1311 additions & 112 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package net.roxymc.jserialize.adapter;
2+
3+
import net.roxymc.jserialize.type.TypeRef;
4+
import org.jspecify.annotations.Nullable;
5+
6+
import static net.roxymc.jserialize.util.ObjectUtils.nonNull;
7+
8+
final class CompositeKeyAdapterFactory implements KeyAdapter.Factory {
9+
private final KeyAdapter.Factory[] factories;
10+
11+
CompositeKeyAdapterFactory(KeyAdapter.Factory[] factories) {
12+
this.factories = nonNull(factories, "factories").clone();
13+
}
14+
15+
@Override
16+
public @Nullable <T> KeyAdapter<T> createKey(TypeRef<T> type, TypeAdapters adapters) {
17+
for (KeyAdapter.Factory factory : factories) {
18+
KeyAdapter<T> adapter = factory.createKey(type, adapters);
19+
20+
if (adapter != null) {
21+
return adapter;
22+
}
23+
}
24+
25+
return null;
26+
}
27+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package net.roxymc.jserialize.adapter;
2+
3+
import net.roxymc.jserialize.type.TypeRef;
4+
import org.jspecify.annotations.Nullable;
5+
6+
import static net.roxymc.jserialize.util.ObjectUtils.nonNull;
7+
8+
final class CompositeTypeAdapterFactory implements TypeAdapter.Factory {
9+
private final TypeAdapter.Factory[] factories;
10+
11+
CompositeTypeAdapterFactory(TypeAdapter.Factory[] factories) {
12+
this.factories = nonNull(factories, "factories").clone();
13+
}
14+
15+
@Override
16+
public @Nullable <T> TypeAdapter<T> create(TypeRef<T> type, TypeAdapters adapters) {
17+
for (TypeAdapter.Factory factory : factories) {
18+
TypeAdapter<T> adapter = factory.create(type, adapters);
19+
20+
if (adapter != null) {
21+
return adapter;
22+
}
23+
}
24+
25+
return null;
26+
}
27+
}

‎core/src/main/java/net/roxymc/jserialize/adapter/KeyAdapter.java‎

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import io.leangen.geantyref.GenericTypeReflector;
44
import net.roxymc.jserialize.type.TypeRef;
5+
import net.roxymc.jserialize.util.TypeUtils;
56
import org.jspecify.annotations.Nullable;
67

78
import java.util.function.Predicate;
@@ -48,6 +49,18 @@ static <T> Factory exactRaw(Class<? super T> type, KeyAdapter<T> adapter) {
4849
return predicate(subtype -> type.equals(subtype.getRawType()), adapter);
4950
}
5051

51-
<T> @Nullable KeyAdapter<T> create(TypeRef<T> type, TypeAdapters adapters);
52+
static <T> Factory exactBoxed(Class<? super T> type, KeyAdapter<T> adapter) {
53+
if (TypeUtils.isPrimitive(type)) {
54+
throw new IllegalArgumentException("type cannot be primitive");
55+
}
56+
57+
return predicate(subtype -> type.equals(GenericTypeReflector.box(subtype.getRawType())), adapter);
58+
}
59+
60+
static Factory composite(Factory... factories) {
61+
return new CompositeKeyAdapterFactory(factories);
62+
}
63+
64+
<T> @Nullable KeyAdapter<T> createKey(TypeRef<T> type, TypeAdapters adapters);
5265
}
5366
}

‎core/src/main/java/net/roxymc/jserialize/adapter/PredicateKeyAdapterFactory.java‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ final class PredicateKeyAdapterFactory implements KeyAdapter.Factory {
1717
}
1818

1919
@Override
20-
public <T> @Nullable KeyAdapter<T> create(TypeRef<T> type, TypeAdapters adapters) {
20+
public <T> @Nullable KeyAdapter<T> createKey(TypeRef<T> type, TypeAdapters adapters) {
2121
@SuppressWarnings("unchecked")
2222
KeyAdapter<T> adapter = (KeyAdapter<T>) this.adapter;
2323
return predicate.test(type) ? adapter : null;

‎core/src/main/java/net/roxymc/jserialize/adapter/ReadContext.java‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
package net.roxymc.jserialize.adapter;
22

3+
import net.roxymc.jserialize.Reader;
34
import net.roxymc.jserialize.adapter.object.FormatUtils;
5+
import net.roxymc.jserialize.type.TypeRef;
46
import org.jetbrains.annotations.ApiStatus;
57
import org.jspecify.annotations.Nullable;
68

9+
import java.io.IOException;
10+
711
public interface ReadContext {
812
@ApiStatus.Internal
913
static ReadContext of(TypeAdapters typeAdapters, FormatUtils<?> formatUtils) {
@@ -20,6 +24,14 @@ static ReadContext of(TypeAdapters typeAdapters, FormatUtils<?> formatUtils) {
2024

2125
ReadContext withKey(@Nullable String key);
2226

27+
default <T> @Nullable T read(Reader reader, Class<T> type) throws IOException {
28+
return read(reader, TypeRef.of(type));
29+
}
30+
31+
default <T> @Nullable T read(Reader reader, TypeRef<T> type) throws IOException {
32+
return typeAdapters().getOrThrow(type).read(reader, type, this);
33+
}
34+
2335
@ApiStatus.Internal
2436
FormatUtils<?> formatUtils();
2537
}

‎core/src/main/java/net/roxymc/jserialize/adapter/TypeAdapter.java‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import net.roxymc.jserialize.Reader;
55
import net.roxymc.jserialize.Writer;
66
import net.roxymc.jserialize.type.TypeRef;
7+
import net.roxymc.jserialize.util.TypeUtils;
78
import org.jetbrains.annotations.Contract;
89
import org.jspecify.annotations.Nullable;
910

@@ -65,6 +66,18 @@ static <T> Factory exactRaw(Class<? super T> type, TypeAdapter<T> adapter) {
6566
return predicate(subtype -> type.equals(subtype.getRawType()), adapter);
6667
}
6768

69+
static <T> Factory exactBoxed(Class<? super T> type, TypeAdapter<T> adapter) {
70+
if (TypeUtils.isPrimitive(type)) {
71+
throw new IllegalArgumentException("type cannot be primitive");
72+
}
73+
74+
return predicate(subtype -> type.equals(GenericTypeReflector.box(subtype.getRawType())), adapter);
75+
}
76+
77+
static Factory composite(Factory... factories) {
78+
return new CompositeTypeAdapterFactory(factories);
79+
}
80+
6881
<T> @Nullable TypeAdapter<T> create(TypeRef<T> type, TypeAdapters adapters);
6982
}
7083
}

‎core/src/main/java/net/roxymc/jserialize/adapter/TypeAdapters.java‎

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,25 @@
11
package net.roxymc.jserialize.adapter;
22

3+
import net.roxymc.jserialize.adapter.array.ArrayAdapter;
4+
import net.roxymc.jserialize.adapter.atomic.AtomicAdapters;
35
import net.roxymc.jserialize.adapter.collection.CollectionAdapter;
46
import net.roxymc.jserialize.adapter.map.MapAdapter;
57
import net.roxymc.jserialize.adapter.object.ObjectAdapter;
8+
import net.roxymc.jserialize.adapter.scalar.EnumAdapter;
69
import net.roxymc.jserialize.adapter.scalar.EnumKeyAdapter;
10+
import net.roxymc.jserialize.adapter.scalar.ScalarAdapters;
711
import net.roxymc.jserialize.adapter.scalar.ScalarKeyAdapters;
812
import net.roxymc.jserialize.type.TypeRef;
913
import org.jetbrains.annotations.ApiStatus;
1014
import org.jspecify.annotations.Nullable;
1115

1216
@ApiStatus.NonExtendable
13-
public interface TypeAdapters {
17+
public interface TypeAdapters extends TypeAdapter.Factory, KeyAdapter.Factory {
1418
TypeAdapters DEFAULT = builder()
19+
.add(ScalarAdapters.factory())
20+
.add(EnumAdapter.factory())
21+
.add(AtomicAdapters.factory())
22+
.add(ArrayAdapter.factory())
1523
.add(CollectionAdapter.factory())
1624
.add(MapAdapter.factory())
1725
.add(ObjectAdapter.annotatedFactory())

‎core/src/main/java/net/roxymc/jserialize/adapter/TypeAdaptersImpl.java‎

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ final class TypeAdaptersImpl implements TypeAdapters {
1818
@SuppressWarnings({"NullableProblems", "DataFlowIssue"}) // IntelliJ has existential issues
1919
private TypeAdaptersImpl(BuilderImpl builder) {
2020
this.typeAdapters = new Registry<>(builder.typeAdapters, (factory, type) -> factory.create(type, this));
21-
this.keyAdapters = new Registry<>(builder.keyAdapters, (factory, type) -> factory.create(type, this));
21+
this.keyAdapters = new Registry<>(builder.keyAdapters, (factory, type) -> factory.createKey(type, this));
2222
}
2323

2424
@Override
@@ -35,6 +35,32 @@ private TypeAdaptersImpl(BuilderImpl builder) {
3535
return adapter;
3636
}
3737

38+
@Override
39+
public @Nullable <T> TypeAdapter<T> create(TypeRef<T> type, TypeAdapters adapters) {
40+
for (TypeAdapter.Factory factory : typeAdapters.factories) {
41+
TypeAdapter<T> adapter = factory.create(type, this);
42+
43+
if (adapter != null) {
44+
return adapter;
45+
}
46+
}
47+
48+
return null;
49+
}
50+
51+
@Override
52+
public @Nullable <T> KeyAdapter<T> createKey(TypeRef<T> type, TypeAdapters adapters) {
53+
for (KeyAdapter.Factory factory : keyAdapters.factories) {
54+
KeyAdapter<T> adapter = factory.createKey(type, this);
55+
56+
if (adapter != null) {
57+
return adapter;
58+
}
59+
}
60+
61+
return null;
62+
}
63+
3864
private static final class Registry<F, A> {
3965
private final Map<AnnotatedType, Optional<A>> cache = new ConcurrentHashMap<>();
4066
private final Set<F> factories;
@@ -80,11 +106,10 @@ public Builder addKey(KeyAdapter.Factory factory) {
80106

81107
@Override
82108
public Builder addAll(TypeAdapters adapters) {
83-
TypeAdaptersImpl adaptersImpl = (TypeAdaptersImpl) nonNull(adapters, "adapters");
84-
85-
typeAdapters.addAll(adaptersImpl.typeAdapters.factories);
86-
keyAdapters.addAll(adaptersImpl.keyAdapters.factories);
109+
nonNull(adapters, "adapters");
87110

111+
typeAdapters.add(adapters);
112+
keyAdapters.add(adapters);
88113
return this;
89114
}
90115

‎core/src/main/java/net/roxymc/jserialize/adapter/WriteContext.java‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
package net.roxymc.jserialize.adapter;
22

3+
import net.roxymc.jserialize.Writer;
34
import net.roxymc.jserialize.adapter.object.FormatUtils;
5+
import net.roxymc.jserialize.type.TypeRef;
46
import org.jetbrains.annotations.ApiStatus;
7+
import org.jetbrains.annotations.Nullable;
8+
9+
import java.io.IOException;
510

611
public interface WriteContext {
712
@ApiStatus.Internal
@@ -11,6 +16,14 @@ static WriteContext of(TypeAdapters typeAdapters, FormatUtils<?> formatUtils) {
1116

1217
TypeAdapters typeAdapters();
1318

19+
default <T> void write(Writer writer, Class<T> type, @Nullable T value) throws IOException {
20+
write(writer, TypeRef.of(type), value);
21+
}
22+
23+
default <T> void write(Writer writer, TypeRef<T> type, @Nullable T value) throws IOException {
24+
typeAdapters().getOrThrow(type).write(writer, type, value, this);
25+
}
26+
1427
@ApiStatus.Internal
1528
FormatUtils<?> formatUtils();
1629
}
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
package net.roxymc.jserialize.adapter.array;
2+
3+
import net.roxymc.jserialize.Reader;
4+
import net.roxymc.jserialize.Writer;
5+
import net.roxymc.jserialize.adapter.ReadContext;
6+
import net.roxymc.jserialize.adapter.TypeAdapter;
7+
import net.roxymc.jserialize.adapter.WriteContext;
8+
import net.roxymc.jserialize.token.TokenTypes;
9+
import net.roxymc.jserialize.type.TypeRef;
10+
import org.jspecify.annotations.Nullable;
11+
12+
import java.io.IOException;
13+
import java.lang.reflect.AnnotatedArrayType;
14+
import java.lang.reflect.AnnotatedType;
15+
import java.lang.reflect.Array;
16+
import java.util.ArrayList;
17+
import java.util.List;
18+
19+
import static net.roxymc.jserialize.adapter.TypeAdapter.Factory.predicate;
20+
21+
public final class ArrayAdapter implements TypeAdapter<Object> {
22+
private static final TypeAdapter.Factory FACTORY = predicate(type -> type.getRawType().isArray(), new ArrayAdapter());
23+
24+
public static TypeAdapter.Factory factory() {
25+
return FACTORY;
26+
}
27+
28+
@Override
29+
public @Nullable Object read(Reader reader, TypeRef<? extends Object> type, ReadContext ctx) throws IOException {
30+
if (!type.getRawType().isArray()) {
31+
throw new IllegalStateException(type.getRawType() + " is not an array");
32+
}
33+
34+
if (reader.peek() == TokenTypes.NULL) {
35+
reader.readNull();
36+
return null;
37+
}
38+
39+
TypeRef<Object> componentType = resolveComponentType(type);
40+
41+
reader.readArrayStart();
42+
43+
List<@Nullable Object> buffer = new ArrayList<>();
44+
45+
while (reader.peek() != TokenTypes.ARRAY_END) {
46+
buffer.add(ctx.read(reader, componentType));
47+
}
48+
49+
reader.readArrayEnd();
50+
51+
Object array = Array.newInstance(componentType.getRawType(), buffer.size());
52+
53+
for (int i = 0; i < buffer.size(); i++) {
54+
Array.set(array, i, buffer.get(i));
55+
}
56+
57+
return array;
58+
}
59+
60+
@Override
61+
public void write(Writer writer, TypeRef<? extends Object> type, @Nullable Object value, WriteContext context) throws IOException {
62+
if (!type.getRawType().isArray()) {
63+
throw new IllegalStateException(type.getRawType() + " is not an array");
64+
}
65+
66+
if (value == null) {
67+
writer.writeNull();
68+
return;
69+
}
70+
71+
TypeRef<Object> componentType = resolveComponentType(type);
72+
73+
writer.writeArrayStart();
74+
75+
int length = Array.getLength(value);
76+
77+
for (int i = 0; i < length; i++) {
78+
context.write(writer, componentType, Array.get(value, i));
79+
}
80+
81+
writer.writeArrayEnd();
82+
}
83+
84+
private TypeRef<Object> resolveComponentType(TypeRef<?> arrayType) {
85+
AnnotatedType type = arrayType.getAnnotatedType();
86+
if (!(type instanceof AnnotatedArrayType)) {
87+
throw new IllegalStateException(arrayType.getType() + " is not an array type");
88+
}
89+
90+
AnnotatedArrayType atype = (AnnotatedArrayType) type;
91+
92+
return TypeRef.of(atype.getAnnotatedGenericComponentType());
93+
}
94+
}

0 commit comments

Comments
 (0)