Skip to content

Commit

Permalink
Add actual codec logic
Browse files Browse the repository at this point in the history
  • Loading branch information
falkreon committed Jul 31, 2024
1 parent 3c31978 commit fb261c9
Show file tree
Hide file tree
Showing 6 changed files with 305 additions and 0 deletions.
40 changes: 40 additions & 0 deletions src/main/java/blue/endless/jankson/api/codec/ClassTargetCodec.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* MIT License
*
* Copyright (c) 2018-2024 Falkreon (Isaac Ellingson)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

package blue.endless.jankson.api.codec;

import java.lang.reflect.Type;

import blue.endless.jankson.impl.magic.ClassHierarchy;

public abstract interface ClassTargetCodec extends StructuredDataCodec {

public abstract Class<?> getTargetClass();

@Override
public default boolean appliesTo(Type t) {
Class<?> clazz = ClassHierarchy.getErasedClass(t);
return getTargetClass().isAssignableFrom(clazz);
}
}
38 changes: 38 additions & 0 deletions src/main/java/blue/endless/jankson/api/codec/CodecHolder.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,44 @@

package blue.endless.jankson.api.codec;

import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;

import javax.annotation.Nullable;

import blue.endless.jankson.api.io.StructuredDataReader;
import blue.endless.jankson.impl.io.objectwriter.SingleValueFunction;

public class CodecHolder implements CodecManager {
private List<StructuredDataCodec> codecs = new ArrayList<>();

@Override
public @Nullable StructuredDataReader getReader(Object o) {
for(StructuredDataCodec codec : codecs) {
if (codec.appliesTo(o)) return codec.getReader(o);
}

return null;
}

@Override
public @Nullable <T> SingleValueFunction<T> getWriter(T existingValue) {
for(StructuredDataCodec codec : codecs) {
if (codec.appliesTo(existingValue.getClass())) return codec.getWriter(existingValue);
}

return null;
}

@Override
public @Nullable <T> SingleValueFunction<T> getWriter(Type t) {
for(StructuredDataCodec codec : codecs) {
if (codec.appliesTo(t)) return codec.getWriter();
}

return null;
}


}
40 changes: 40 additions & 0 deletions src/main/java/blue/endless/jankson/api/codec/CodecManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,46 @@

package blue.endless.jankson.api.codec;

import java.lang.reflect.Type;

import javax.annotation.Nullable;

import blue.endless.jankson.api.io.StructuredDataReader;
import blue.endless.jankson.impl.io.objectwriter.SingleValueFunction;

/**
* Understands the structure of certain java object types, and can create streams to produce or
* consume StructuredData. You can think of this as a factory for serializers and deserializers.
*/
public interface CodecManager {
/**
* Gets a StructuredDataReader which can produce a stream of data that represents the provided
* object.
* @param o The object to produce a data stream for
* @return A stream of StructuredData which represents the provided object, or null if the object
* isn't understood by this manager or any of its delegates.
*/
public @Nullable StructuredDataReader getReader(Object o);

/**
* Gets a StructuredDataWriter that can consume a stream of data and produce an object of the
* same type as the provided object.
* @param <T> The type of the object that should be produced
* @param existingValue The previous value of the field, which can be reused if the object is
* mutable. The codec is not obligated to reuse the object, but it MAY
* decide to.
* @return A StructuredDataWriter that can consume a stream for this object's type, or null if
* the type isn't understood by this manager or any of its delegates.
*/
public @Nullable <T> SingleValueFunction<T> getWriter(T existingValue);

/**
* Gets a StructuredDataWriter that can consume a stream of data and produce an object of the
* provided type.
* @param <T> The type of object to produce
* @param t The type of object to produce
* @return A StructuredDataWriter that can consume data for this type and produce an instance of
* it.
*/
public @Nullable <T> SingleValueFunction<T> getWriter(Type t);
}
60 changes: 60 additions & 0 deletions src/main/java/blue/endless/jankson/api/codec/FullCodec.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* MIT License
*
* Copyright (c) 2018-2024 Falkreon (Isaac Ellingson)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

package blue.endless.jankson.api.codec;

import java.util.function.Function;
import java.util.function.Supplier;

import blue.endless.jankson.api.io.StructuredDataReader;
import blue.endless.jankson.impl.io.objectwriter.SingleValueFunction;

public class FullCodec implements ClassTargetCodec {
private final Class<?> targetClass;
private final Function<Object, StructuredDataReader> serializer;
private final Supplier<SingleValueFunction<Object>> deserializer;

@SuppressWarnings("unchecked")
public <T> FullCodec(Class<T> targetClass, Function<T, StructuredDataReader> serializer, Supplier<SingleValueFunction<T>> deserializer) {
this.targetClass = targetClass;
this.serializer = (Function<Object, StructuredDataReader>) serializer;
this.deserializer = () -> (SingleValueFunction<Object>) deserializer.get();
}

@Override
public StructuredDataReader getReader(Object o) {
return serializer.apply(o);
}

@SuppressWarnings("unchecked")
@Override
public <T> SingleValueFunction<T> getWriter() {
return (SingleValueFunction<T>) deserializer.get();
}

@Override
public Class<?> getTargetClass() {
return targetClass;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@
import blue.endless.jankson.api.io.StructuredDataReader;
import blue.endless.jankson.impl.io.objectwriter.SingleValueFunction;

/**
* Factory for StructuredDataReaders and StructuredDataWriters for a particular type.
*/
public interface StructuredDataCodec {
/**
* Returns true if this codec can be used to create a StructuredData stream about the provided
Expand Down Expand Up @@ -56,6 +59,19 @@ public default boolean appliesTo(Object o) {
*/
public StructuredDataReader getReader(Object o);

/**
* Gets a StructuredDataWriter that can consume a stream of structured data and produce an
* object of the kind that this codec manages.
* @param <T> The type of the object this codec manages
* @param existingValue The previous value of the field, which can be reused if the object is
* mutable. The codec is not obligated to reuse the object, but it MAY
* decide to.
* @return A StructuredDataWriter that can consume a stream for this type.
*/
public default <T> SingleValueFunction<T> getWriter(T existingValue) {
return getWriter();
}

/**
* Gets a StructuredDataWriter that can consume a stream of structured data and produce an
* object of the kind that this codec manages.
Expand Down
111 changes: 111 additions & 0 deletions src/main/java/blue/endless/jankson/api/codec/ValueElementCodec.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/*
* MIT License
*
* Copyright (c) 2018-2024 Falkreon (Isaac Ellingson)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

package blue.endless.jankson.api.codec;

import java.io.IOException;
import java.util.function.Function;

import blue.endless.jankson.api.document.ArrayElement;
import blue.endless.jankson.api.document.ObjectElement;
import blue.endless.jankson.api.document.PrimitiveElement;
import blue.endless.jankson.api.document.ValueElement;
import blue.endless.jankson.api.function.CheckedFunction;
import blue.endless.jankson.api.io.StructuredDataReader;
import blue.endless.jankson.api.io.ValueElementReader;
import blue.endless.jankson.impl.io.objectwriter.SingleValueFunction;

/**
* Simple codec that converts an object to and from at-rest json data. This is similar to Jankson
* 1.2-era serializers and deserializers.
*/
public class ValueElementCodec implements ClassTargetCodec {
private final Class<?> targetClass;
private final Function<Object, ValueElement> serializer;
private final CheckedFunction<ValueElement, Object, IOException> deserializer;

@SuppressWarnings("unchecked")
public <T> ValueElementCodec(Class<T> targetClass, Function<T, ValueElement> serializer, CheckedFunction<ValueElement, T, IOException> deserializer) {
this.targetClass = targetClass;
this.serializer = (Function<Object, ValueElement>) serializer;
this.deserializer = (CheckedFunction<ValueElement, Object, IOException>) deserializer;
}

@Override
public Class<?> getTargetClass() {
return targetClass;
}

@Override
public StructuredDataReader getReader(Object o) {
return ValueElementReader.of(serializer.apply(o));
}

@Override
public <T> SingleValueFunction<T> getWriter() {
return null; //TODO: Implement
}

public <T> ValueElementCodec requiringObjects(Class<T> targetClass, Function<T, ObjectElement> serializer, Function<ObjectElement, T> deserializer) {
Function<T, ValueElement> shimmedSerializer = serializer::apply;

CheckedFunction<ValueElement, T, IOException> shimmedDeserializer = (elem) -> {
if (elem instanceof ObjectElement object) {
return deserializer.apply(object);
} else {
throw new IOException("Required ObjectElement but found "+elem.getClass().getSimpleName());
}
};

return new ValueElementCodec(targetClass, shimmedSerializer, shimmedDeserializer);
}

public <T> ValueElementCodec requiringArrays(Class<T> targetClass, Function<T, ArrayElement> serializer, Function<ArrayElement, T> deserializer) {
Function<T, ValueElement> shimmedSerializer = serializer::apply;

CheckedFunction<ValueElement, T, IOException> shimmedDeserializer = (elem) -> {
if (elem instanceof ArrayElement array) {
return deserializer.apply(array);
} else {
throw new IOException("Required ArrayElement but found "+elem.getClass().getSimpleName());
}
};

return new ValueElementCodec(targetClass, shimmedSerializer, shimmedDeserializer);
}

public <T> ValueElementCodec requiringPrimitives(Class<T> targetClass, Function<T, PrimitiveElement> serializer, Function<PrimitiveElement, T> deserializer) {
Function<T, ValueElement> shimmedSerializer = serializer::apply;

CheckedFunction<ValueElement, T, IOException> shimmedDeserializer = (elem) -> {
if (elem instanceof PrimitiveElement primitive) {
return deserializer.apply(primitive);
} else {
throw new IOException("Required PrimitiveElement but found "+elem.getClass().getSimpleName());
}
};

return new ValueElementCodec(targetClass, shimmedSerializer, shimmedDeserializer);
}
}

0 comments on commit fb261c9

Please sign in to comment.