Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package net.roxymc.jserialize.adapter;

import org.jspecify.annotations.Nullable;

import static net.roxymc.jserialize.util.ObjectUtils.nonNull;

public abstract class AbstractKeyAdapter<T> implements KeyAdapter<T> {
protected AbstractKeyAdapter() {
}

@Override
public final @Nullable T decode(@Nullable String value) {
return value != null ? parse(value) : null;
}

protected abstract T parse(String value);

@Override
public final String encode(@Nullable T value) {
return nonNull(value, "value").toString();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package net.roxymc.jserialize.adapter;

import net.roxymc.jserialize.type.TypeRef;
import org.jspecify.annotations.Nullable;

import static net.roxymc.jserialize.util.ObjectUtils.nonNull;

final class CompositeKeyAdapterFactory implements KeyAdapter.Factory {
private final KeyAdapter.Factory[] factories;

CompositeKeyAdapterFactory(KeyAdapter.Factory[] factories) {
this.factories = nonNull(factories, "factories").clone();
}

@Override
public @Nullable <T> KeyAdapter<T> createKey(TypeRef<T> type, TypeAdapters adapters) {
for (KeyAdapter.Factory factory : factories) {
KeyAdapter<T> adapter = factory.createKey(type, adapters);

if (adapter != null) {
return adapter;
}
}

return null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package net.roxymc.jserialize.adapter;

import net.roxymc.jserialize.type.TypeRef;
import org.jspecify.annotations.Nullable;

import static net.roxymc.jserialize.util.ObjectUtils.nonNull;

final class CompositeTypeAdapterFactory implements TypeAdapter.Factory {
private final TypeAdapter.Factory[] factories;

CompositeTypeAdapterFactory(TypeAdapter.Factory[] factories) {
this.factories = nonNull(factories, "factories").clone();
}

@Override
public @Nullable <T> TypeAdapter<T> create(TypeRef<T> type) {
for (TypeAdapter.Factory factory : factories) {
TypeAdapter<T> adapter = factory.create(type);

if (adapter != null) {
return adapter;
}
}

return null;
}
}
47 changes: 22 additions & 25 deletions core/src/main/java/net/roxymc/jserialize/adapter/KeyAdapter.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,47 +7,44 @@
import java.util.function.Predicate;

public interface KeyAdapter<T> extends KeyDecoder<T>, KeyEncoder<T> {
static <T> KeyAdapter<T> of(KeyDecoder<T> decoder, KeyEncoder<T> encoder) {
return new KeyAdapter<>() {
@Override
public @Nullable T decode(@Nullable String value) {
return decoder.decode(value);
}

@Override
public String encode(@Nullable T value) {
return encoder.encode(value);
}
};
}

@Override
@Nullable T decode(@Nullable String value);

@Override
String encode(@Nullable T value);

TypeRef<? extends T> type();

interface Factory {
static Factory predicate(Predicate<? super TypeRef<?>> predicate, KeyAdapter<?> adapter) {
return new PredicateKeyAdapterFactory(predicate, adapter);
static <T> Factory where(Predicate<? super TypeRef<?>> predicate, TypedFactory<? super T> factory) {
return new PredicateKeyAdapterFactory(predicate, factory);
}

static <T> Factory polymorphic(Class<? super T> type, KeyAdapter<T> adapter) {
return predicate(subtype -> type.isAssignableFrom(subtype.getRawType()), adapter);
static <T> Factory polymorphic(Class<T> type, TypedFactory<? super T> factory) {
return where(subtype -> type.isAssignableFrom(subtype.getRawType()), factory);
}

static <T> Factory polymorphic(TypeRef<? extends T> type, KeyAdapter<T> adapter) {
return predicate(subtype -> GenericTypeReflector.isSuperType(type.getType(), subtype.getType()), adapter);
static <T> Factory polymorphic(TypeRef<T> type, TypedFactory<? super T> factory) {
return where(subtype -> GenericTypeReflector.isSuperType(type.getType(), subtype.getType()), factory);
}

static <T> Factory exact(TypeRef<? extends T> type, KeyAdapter<T> adapter) {
return predicate(subtype -> type.getType().equals(subtype.getType()), adapter);
static <T> Factory exact(KeyAdapter<T> adapter) {
return Factory.<T>where(subtype -> adapter.type().getType().equals(subtype.getType()), ($1, $2) -> adapter);
}

static <T> Factory exactRaw(Class<? super T> type, KeyAdapter<T> adapter) {
return predicate(subtype -> type.equals(subtype.getRawType()), adapter);
static <T> Factory exactRaw(Class<T> type, TypedFactory<? super T> factory) {
return where(subtype -> type.equals(subtype.getRawType()), factory);
}

<T> @Nullable KeyAdapter<T> create(TypeRef<T> type, TypeAdapters adapters);
static Factory composite(Factory... factories) {
return new CompositeKeyAdapterFactory(factories);
}

<T> @Nullable KeyAdapter<T> createKey(TypeRef<T> type, TypeAdapters adapters);
}

@FunctionalInterface
interface TypedFactory<T> {
@Nullable KeyAdapter<T> createKey(TypeRef<T> type, TypeAdapters adapters);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,22 @@
import static net.roxymc.jserialize.util.ObjectUtils.nonNull;

final class PredicateKeyAdapterFactory implements KeyAdapter.Factory {
private final KeyAdapter<?> adapter;
private final Predicate<? super TypeRef<?>> predicate;
private final KeyAdapter.TypedFactory<?> factory;

PredicateKeyAdapterFactory(Predicate<? super TypeRef<?>> predicate, KeyAdapter<?> adapter) {
this.adapter = nonNull(adapter, "adapter");
PredicateKeyAdapterFactory(Predicate<? super TypeRef<?>> predicate, KeyAdapter.TypedFactory<?> factory) {
this.predicate = nonNull(predicate, "predicate");
this.factory = nonNull(factory, "factory");
}

@Override
public <T> @Nullable KeyAdapter<T> create(TypeRef<T> type, TypeAdapters adapters) {
public <T> @Nullable KeyAdapter<T> createKey(TypeRef<T> type, TypeAdapters adapters) {
if (!predicate.test(type)) {
return null;
}

@SuppressWarnings("unchecked")
KeyAdapter<T> adapter = (KeyAdapter<T>) this.adapter;
return predicate.test(type) ? adapter : null;
KeyAdapter<T> adapter = ((KeyAdapter.TypedFactory<T>) this.factory).createKey(type, adapters);
return adapter;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,22 @@
import static net.roxymc.jserialize.util.ObjectUtils.nonNull;

final class PredicateTypeAdapterFactory implements TypeAdapter.Factory {
private final TypeAdapter<?> adapter;
private final Predicate<? super TypeRef<?>> predicate;
private final TypeAdapter.TypedFactory<?> factory;

PredicateTypeAdapterFactory(Predicate<? super TypeRef<?>> predicate, TypeAdapter<?> adapter) {
this.adapter = nonNull(adapter, "adapter");
PredicateTypeAdapterFactory(Predicate<? super TypeRef<?>> predicate, TypeAdapter.TypedFactory<?> factory) {
this.predicate = nonNull(predicate, "predicate");
this.factory = nonNull(factory, "factory");
}

@Override
public <T> @Nullable TypeAdapter<T> create(TypeRef<T> type, TypeAdapters adapters) {
public <T> @Nullable TypeAdapter<T> create(TypeRef<T> type) {
if (!predicate.test(type)) {
return null;
}

@SuppressWarnings("unchecked")
TypeAdapter<T> adapter = (TypeAdapter<T>) this.adapter;
return predicate.test(type) ? adapter : null;
TypeAdapter<T> adapter = ((TypeAdapter.TypedFactory<T>) this.factory).create(type);
return adapter;
}
}
12 changes: 12 additions & 0 deletions core/src/main/java/net/roxymc/jserialize/adapter/ReadContext.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
package net.roxymc.jserialize.adapter;

import net.roxymc.jserialize.Reader;
import net.roxymc.jserialize.adapter.object.FormatUtils;
import net.roxymc.jserialize.type.TypeRef;
import org.jetbrains.annotations.ApiStatus;
import org.jspecify.annotations.Nullable;

import java.io.IOException;

public interface ReadContext {
@ApiStatus.Internal
static ReadContext of(TypeAdapters typeAdapters, FormatUtils<?> formatUtils) {
Expand All @@ -20,6 +24,14 @@ static ReadContext of(TypeAdapters typeAdapters, FormatUtils<?> formatUtils) {

ReadContext withKey(@Nullable String key);

default <T> @Nullable T read(Reader reader, Class<T> type) throws IOException {
return read(reader, TypeRef.of(type));
}

default <T> @Nullable T read(Reader reader, TypeRef<T> type) throws IOException {
return typeAdapters().getOrThrow(type).read(reader, this);
}

@ApiStatus.Internal
FormatUtils<?> formatUtils();
}
62 changes: 28 additions & 34 deletions core/src/main/java/net/roxymc/jserialize/adapter/TypeAdapter.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,60 +11,54 @@
import java.util.function.Predicate;

public interface TypeAdapter<T> extends TypeReader<T>, TypeWriter<T> {
static <T> TypeAdapter<T> of(TypeReader<T> reader, TypeWriter<T> writer) {
return new TypeAdapter<>() {
private final TypeReader<T> reader0 = reader;
private final TypeWriter<T> writer0 = writer;

@Override
public @Nullable T read(Reader reader, TypeRef<? extends T> type, ReadContext context) throws IOException {
return reader0.read(reader, type, context);
}

@Override
public void write(Writer writer, TypeRef<? extends T> type, @Nullable T value, WriteContext context) throws IOException {
writer0.write(writer, type, value, context);
}
};
}

@Override
@Nullable T read(Reader reader, TypeRef<? extends T> type, ReadContext context) throws IOException;
@Nullable T read(Reader reader, ReadContext context) throws IOException;

@Override
void write(Writer writer, TypeRef<? extends T> type, @Nullable T value, WriteContext context) throws IOException;
void write(Writer writer, @Nullable T value, WriteContext context) throws IOException;

TypeRef<? extends T> type();

interface Mutable<T> extends TypeAdapter<T> {
@Override
default @Nullable T read(Reader reader, TypeRef<? extends T> type, ReadContext context) throws IOException {
return mutate(reader, type, null, context);
default @Nullable T read(Reader reader, ReadContext context) throws IOException {
return mutate(reader, null, context);
}

@Contract("_, _, !null, _ -> param3")
@Nullable T mutate(Reader reader, TypeRef<? extends T> type, @Nullable T value, ReadContext context) throws IOException;
@Contract("_, !null, _ -> param2")
@Nullable T mutate(Reader reader, @Nullable T value, ReadContext context) throws IOException;
}

interface Factory {
static Factory predicate(Predicate<? super TypeRef<?>> predicate, TypeAdapter<?> adapter) {
return new PredicateTypeAdapterFactory(predicate, adapter);
static <T> Factory where(Predicate<? super TypeRef<?>> predicate, TypedFactory<? super T> factory) {
return new PredicateTypeAdapterFactory(predicate, factory);
}

static <T> Factory polymorphic(Class<? super T> type, TypeAdapter<T> adapter) {
return predicate(subtype -> type.isAssignableFrom(subtype.getRawType()), adapter);
static <T> Factory polymorphic(Class<T> type, TypedFactory<? super T> factory) {
return where(subtype -> type.isAssignableFrom(subtype.getRawType()), factory);
}

static <T> Factory polymorphic(TypeRef<? extends T> type, TypeAdapter<T> adapter) {
return predicate(subtype -> GenericTypeReflector.isSuperType(type.getType(), subtype.getType()), adapter);
static <T> Factory polymorphic(TypeRef<T> type, TypedFactory<? super T> factory) {
return where(subtype -> GenericTypeReflector.isSuperType(type.getType(), subtype.getType()), factory);
}

static <T> Factory exact(TypeRef<? extends T> type, TypeAdapter<T> adapter) {
return predicate(subtype -> type.getType().equals(subtype.getType()), adapter);
static <T> Factory exact(TypeAdapter<T> adapter) {
return Factory.<T>where(subtype -> adapter.type().getType().equals(subtype.getType()), $ -> adapter);
}

static <T> Factory exactRaw(Class<? super T> type, TypeAdapter<T> adapter) {
return predicate(subtype -> type.equals(subtype.getRawType()), adapter);
static <T> Factory exactRaw(Class<T> type, TypedFactory<? super T> factory) {
return where(subtype -> type.equals(subtype.getRawType()), factory);
}

<T> @Nullable TypeAdapter<T> create(TypeRef<T> type, TypeAdapters adapters);
static Factory composite(Factory... factories) {
return new CompositeTypeAdapterFactory(factories);
}

<T> @Nullable TypeAdapter<T> create(TypeRef<T> type);
}

@FunctionalInterface
interface TypedFactory<T> {
@Nullable TypeAdapter<T> create(TypeRef<T> type);
}
}
Original file line number Diff line number Diff line change
@@ -1,22 +1,34 @@
package net.roxymc.jserialize.adapter;

import net.roxymc.jserialize.adapter.array.ArrayAdapter;
import net.roxymc.jserialize.adapter.atomic.AtomicAdapters;
import net.roxymc.jserialize.adapter.collection.CollectionAdapter;
import net.roxymc.jserialize.adapter.map.MapAdapter;
import net.roxymc.jserialize.adapter.object.ObjectAdapter;
import net.roxymc.jserialize.adapter.scalar.EnumAdapter;
import net.roxymc.jserialize.adapter.scalar.EnumKeyAdapter;
import net.roxymc.jserialize.adapter.scalar.ScalarAdapters;
import net.roxymc.jserialize.adapter.scalar.ScalarKeyAdapters;
import net.roxymc.jserialize.adapter.temporal.TemporalAdapters;
import net.roxymc.jserialize.adapter.temporal.TemporalKeyAdapters;
import net.roxymc.jserialize.type.TypeRef;
import org.jetbrains.annotations.ApiStatus;
import org.jspecify.annotations.Nullable;

@ApiStatus.NonExtendable
public interface TypeAdapters {
public interface TypeAdapters extends TypeAdapter.Factory, KeyAdapter.Factory {
TypeAdapters DEFAULT = builder()
.add(ScalarAdapters.factory())
.add(EnumAdapter.factory())
.add(AtomicAdapters.factory())
.add(TemporalAdapters.factory())
.add(ArrayAdapter.factory())
.add(CollectionAdapter.factory())
.add(MapAdapter.factory())
.add(ObjectAdapter.annotatedFactory())
.addKey(ScalarKeyAdapters.factory())
.addKey(EnumKeyAdapter.factory())
.addKey(TemporalKeyAdapters.factory())
.build();

static Builder builder() {
Expand Down Expand Up @@ -61,6 +73,12 @@ default <T> KeyAdapter<T> getKeyOrThrow(TypeRef<T> type) {
throw new IllegalStateException("Could not find key adapter for " + type.getAnnotatedType());
}

@Override
@Nullable <T> TypeAdapter<T> create(TypeRef<T> type);

@Override
@Nullable <T> KeyAdapter<T> createKey(TypeRef<T> type, TypeAdapters adapters);

@ApiStatus.NonExtendable
interface Builder {
Builder add(TypeAdapter.Factory factory);
Expand Down
Loading
Loading