From c055eb0658552f0c2eae69b782ea1912d96e9b13 Mon Sep 17 00:00:00 2001 From: Falkreon Date: Wed, 24 Jul 2024 11:24:05 -0500 Subject: [PATCH] Rename StructuredDataPipe to StructuredDataBuffer, implement ValueElementReader --- .../jankson/api/DeserializerFunction.java | 43 -- .../jankson/api/io/JsonReaderOptions.java | 14 - .../jankson/api/io/JsonWriterOptions.java | 10 +- .../jankson/api/io/ValueElementReader.java | 93 ++++ .../api/serializer/ObjectReaderFactory.java | 94 ++++ .../serializer/package-info.java} | 10 +- .../endless/jankson/impl/MarshallerImpl.java | 434 ------------------ .../jankson/impl/POJODeserializer.java | 295 ------------ .../impl/io/AbstractStructuredDataReader.java | 2 +- ...ataPipe.java => StructuredDataBuffer.java} | 7 +- .../ArrayStructuredDataReader.java | 6 +- .../CollectionStructuredDataReader.java | 6 +- .../DelegatingStructuredDataReader.java | 28 +- .../objectreader/MapStructuredDataReader.java | 8 +- .../ObjectStructuredDataReader.java | 10 +- .../impl/serializer/CommentSerializer.java | 99 ---- .../serializer/DeserializerFunctionPool.java | 86 ---- 17 files changed, 223 insertions(+), 1022 deletions(-) delete mode 100644 src/main/java/blue/endless/jankson/api/DeserializerFunction.java create mode 100644 src/main/java/blue/endless/jankson/api/io/ValueElementReader.java create mode 100644 src/main/java/blue/endless/jankson/api/serializer/ObjectReaderFactory.java rename src/main/java/blue/endless/jankson/{impl/serializer/InternalDeserializerFunction.java => api/serializer/package-info.java} (80%) delete mode 100644 src/main/java/blue/endless/jankson/impl/MarshallerImpl.java delete mode 100644 src/main/java/blue/endless/jankson/impl/POJODeserializer.java rename src/main/java/blue/endless/jankson/impl/io/{StructuredDataPipe.java => StructuredDataBuffer.java} (93%) delete mode 100644 src/main/java/blue/endless/jankson/impl/serializer/CommentSerializer.java delete mode 100644 src/main/java/blue/endless/jankson/impl/serializer/DeserializerFunctionPool.java diff --git a/src/main/java/blue/endless/jankson/api/DeserializerFunction.java b/src/main/java/blue/endless/jankson/api/DeserializerFunction.java deleted file mode 100644 index 23e93b4..0000000 --- a/src/main/java/blue/endless/jankson/api/DeserializerFunction.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * 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; - -import blue.endless.jankson.api.io.JsonIOException; -import blue.endless.jankson.impl.serializer.InternalDeserializerFunction; - -@FunctionalInterface -public interface DeserializerFunction extends InternalDeserializerFunction { - public B apply(A a, Marshaller m) throws JsonIOException; - - @SuppressWarnings("unchecked") - @Override - default B deserialize(Object a, Marshaller m) throws JsonIOException { - try { - return apply((A)a, m); - } catch (ClassCastException ex) { - throw new JsonIOException(ex); - } - } -} diff --git a/src/main/java/blue/endless/jankson/api/io/JsonReaderOptions.java b/src/main/java/blue/endless/jankson/api/io/JsonReaderOptions.java index 598b3fa..eb87b57 100644 --- a/src/main/java/blue/endless/jankson/api/io/JsonReaderOptions.java +++ b/src/main/java/blue/endless/jankson/api/io/JsonReaderOptions.java @@ -26,10 +26,6 @@ import java.util.EnumSet; -import blue.endless.jankson.api.Marshaller; -import blue.endless.jankson.impl.MarshallerImpl; - -@SuppressWarnings("deprecation") public class JsonReaderOptions { /** * This is the set of options configured when there are no options specified. Effectively this is the "default @@ -38,25 +34,15 @@ public class JsonReaderOptions { public static final JsonReaderOptions UNSPECIFIED = new JsonReaderOptions(Hint.ALLOW_UNQUOTED_KEYS); private final EnumSet hints = EnumSet.noneOf(Hint.class); - private final Marshaller marshaller; public JsonReaderOptions(Hint... hints) { - this.marshaller = MarshallerImpl.getFallback(); - } - - public JsonReaderOptions(Marshaller marshaller, Hint... hints) { for(Hint hint : hints) this.hints.add(hint); - this.marshaller = marshaller; } public boolean hasHint(Hint hint) { return hints.contains(hint); } - public Marshaller getMarshaller() { - return this.marshaller; - } - public enum Hint { /** Allow the root object of a document to omit its delimiters / braces */ ALLOW_BARE_ROOT_OBJECT, diff --git a/src/main/java/blue/endless/jankson/api/io/JsonWriterOptions.java b/src/main/java/blue/endless/jankson/api/io/JsonWriterOptions.java index e760215..056fadb 100644 --- a/src/main/java/blue/endless/jankson/api/io/JsonWriterOptions.java +++ b/src/main/java/blue/endless/jankson/api/io/JsonWriterOptions.java @@ -26,10 +26,6 @@ import java.util.EnumSet; -import blue.endless.jankson.api.Marshaller; -import blue.endless.jankson.impl.MarshallerImpl; - -@SuppressWarnings("deprecation") public class JsonWriterOptions { public static JsonWriterOptions DEFAULTS = new JsonWriterOptions(Hint.UNQUOTED_KEYS, Hint.WRITE_COMMENTS, Hint.WRITE_NEWLINES, Hint.WRITE_WHITESPACE); public static JsonWriterOptions ONE_LINE = new JsonWriterOptions(Hint.UNQUOTED_KEYS, Hint.WRITE_COMMENTS, Hint.WRITE_WHITESPACE); @@ -38,15 +34,13 @@ public class JsonWriterOptions { private final EnumSet hints = EnumSet.noneOf(Hint.class); private final String indentString; - private final Marshaller marshaller; public JsonWriterOptions(Hint... hints) { - this("\t", MarshallerImpl.getFallback(), hints); + this("\t", hints); } - public JsonWriterOptions(String indentString, Marshaller marshaller, Hint... hints) { + public JsonWriterOptions(String indentString, Hint... hints) { for(Hint hint : hints) this.hints.add(hint); - this.marshaller = marshaller; this.indentString = indentString; } diff --git a/src/main/java/blue/endless/jankson/api/io/ValueElementReader.java b/src/main/java/blue/endless/jankson/api/io/ValueElementReader.java new file mode 100644 index 0000000..0e57abb --- /dev/null +++ b/src/main/java/blue/endless/jankson/api/io/ValueElementReader.java @@ -0,0 +1,93 @@ +/* + * 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.io; + +import java.io.IOException; +import java.util.Iterator; +import java.util.Map; + +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.impl.io.StructuredDataBuffer; +import blue.endless.jankson.impl.io.objectreader.DelegatingStructuredDataReader; + +public class ValueElementReader { + + private ValueElementReader() {} + + public static StructuredDataReader of(ValueElement val) { + if (val instanceof PrimitiveElement primitive) { + StructuredDataBuffer buf = new StructuredDataBuffer(); + buf.write(StructuredData.primitive(primitive)); + return buf; + } else if (val instanceof ArrayElement array) { + return new ArrayValueReader(array); + } else if (val instanceof ObjectElement object) { + return new ObjectValueReader(object); + } else { + throw new IllegalArgumentException("Unknown element type"); + } + } + + private static class ArrayValueReader extends DelegatingStructuredDataReader { + private final Iterator iterator; + + public ArrayValueReader(ArrayElement value) { + this.iterator = value.iterator(); + } + + @Override + protected void onDelegateEmpty() throws IOException { + if (iterator.hasNext()) { + ValueElement cur = iterator.next(); + setDelegate(of(cur)); + } else { + buffer(StructuredData.EOF); + } + } + } + + private static class ObjectValueReader extends DelegatingStructuredDataReader { + private final Iterator> iterator; + + public ObjectValueReader(ObjectElement value) { + iterator = value.entrySet().iterator(); + } + + @Override + protected void onDelegateEmpty() throws IOException { + if (iterator.hasNext()) { + Map.Entry entry = iterator.next(); + buffer(StructuredData.objectKey(entry.getKey())); + setDelegate(ValueElementReader.of(entry.getValue())); + } else { + buffer(StructuredData.EOF); + } + } + + } +} diff --git a/src/main/java/blue/endless/jankson/api/serializer/ObjectReaderFactory.java b/src/main/java/blue/endless/jankson/api/serializer/ObjectReaderFactory.java new file mode 100644 index 0000000..6d0086f --- /dev/null +++ b/src/main/java/blue/endless/jankson/api/serializer/ObjectReaderFactory.java @@ -0,0 +1,94 @@ +/* + * 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.serializer; + +import java.lang.reflect.AnnotatedType; +import java.lang.reflect.Type; +import java.util.HashMap; +import java.util.Map; +import java.util.function.Function; + +import blue.endless.jankson.api.document.ValueElement; +import blue.endless.jankson.api.io.StructuredDataReader; +import blue.endless.jankson.api.io.ValueElementReader; +import blue.endless.jankson.impl.io.objectreader.ObjectStructuredDataReader; + +public class ObjectReaderFactory { + private Map> functionMap = new HashMap<>(); + + /** + * Registers a "classic" serializer for the specified type. + * @param The type the serializer will apply to + * @param type The class the serializer will apply to + * @param function A function that will receive an object of the specified type, and produce a + * ValueElement representing it. + */ + @SuppressWarnings("unchecked") + public void register(final Class type, final Function function) { + register((Type) type, (Function) function); + } + + /** + * Registers a "classic" serializer for the specified type + * @param type The type to specify a serializer for + * @param function A function which will receive an object of the specified type, and produce a + * ValueElement representing it. + */ + public void register(final Type type, final Function function) { + Function supplier = (Object obj) -> ValueElementReader.of(function.apply(obj)); + functionMap.put(type, supplier); + } + + + + /** + * Gets a reader which will provide a StructuredData representation of the provided object + * @param The type of the object being serialized / read + * @param type The class of the object being serialized / read + * @param objectOfType The object being serialized / read + * @return A StructuredDataReader which will provide data representing the object + */ + public StructuredDataReader getReader(final Class type, final T objectOfType) { + return getReader((Type) type, objectOfType); + } + + /** + * Gets a reader which will provide a StructuredData representation of the provided object + * @param type The type of the object being serialized / read + * @param objectOfType The object being serialized / read + * @return A StructuredDataReader which will provide data representing the object + */ + public StructuredDataReader getReader(Type type, final Object objectOfType) { + // Strip annotations - we don't want to differentiate between String and @Nullable String. + if (type instanceof AnnotatedType annoType) { + type = annoType.getType(); + } + + Function function = functionMap.get(type); + return (function == null) ? + ObjectStructuredDataReader.of(objectOfType) : + function.apply(objectOfType); + } +} diff --git a/src/main/java/blue/endless/jankson/impl/serializer/InternalDeserializerFunction.java b/src/main/java/blue/endless/jankson/api/serializer/package-info.java similarity index 80% rename from src/main/java/blue/endless/jankson/impl/serializer/InternalDeserializerFunction.java rename to src/main/java/blue/endless/jankson/api/serializer/package-info.java index 9e55303..880b65a 100644 --- a/src/main/java/blue/endless/jankson/impl/serializer/InternalDeserializerFunction.java +++ b/src/main/java/blue/endless/jankson/api/serializer/package-info.java @@ -22,12 +22,4 @@ * SOFTWARE. */ -package blue.endless.jankson.impl.serializer; - -import blue.endless.jankson.api.Marshaller; -import blue.endless.jankson.api.io.JsonIOException; - -@FunctionalInterface -public interface InternalDeserializerFunction { - public B deserialize(Object a, Marshaller m) throws JsonIOException; -} +package blue.endless.jankson.api.serializer; diff --git a/src/main/java/blue/endless/jankson/impl/MarshallerImpl.java b/src/main/java/blue/endless/jankson/impl/MarshallerImpl.java deleted file mode 100644 index 38a081f..0000000 --- a/src/main/java/blue/endless/jankson/impl/MarshallerImpl.java +++ /dev/null @@ -1,434 +0,0 @@ -/* - * 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.impl; - -import java.lang.reflect.Type; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.function.Function; -import java.util.function.Supplier; - -import blue.endless.jankson.api.document.DocumentElement; -import blue.endless.jankson.api.DeserializerFunction; -import blue.endless.jankson.api.Marshaller; -import blue.endless.jankson.api.MarshallerException; -import blue.endless.jankson.impl.serializer.DeserializerFunctionPool; - - -public class MarshallerImpl implements blue.endless.jankson.api.Marshaller { - private static MarshallerImpl INSTANCE = new MarshallerImpl(); - - public static Marshaller getFallback() { return INSTANCE; } - - private Map, Function> primitiveMarshallers = new HashMap<>(); - //Map, Function> typeAdapters = new HashMap<>(); - - //private Map, BiFunction> serializers = new HashMap<>(); - private Map, DeserializerFunctionPool> deserializers = new HashMap<>(); - private Map, Supplier> typeFactories = new HashMap<>(); - - public void register(Class clazz, Function marshaller) { - primitiveMarshallers.put(clazz, marshaller); - } - - public void registerTypeFactory(Class clazz, Supplier supplier) { - typeFactories.put(clazz, supplier); - } - - public void registerDeserializer(Class sourceClass, Class targetClass, DeserializerFunction function) { - @SuppressWarnings("unchecked") - DeserializerFunctionPool pool = (DeserializerFunctionPool)deserializers.get(targetClass); - if (pool==null) { - pool = new DeserializerFunctionPool(targetClass); - deserializers.put(targetClass, pool); - } - pool.registerUnsafe(sourceClass, function); - } - - public MarshallerImpl() { - register(Void.class, (it)->null); - - register(String.class, (it)->it.toString()); - - register(Byte.class, (it)->(it instanceof Number) ? ((Number)it).byteValue() : null); - register(Character.class, (it)->(it instanceof Number) ? (char)((Number)it).shortValue() : it.toString().charAt(0)); - register(Short.class, (it)->(it instanceof Number) ? ((Number)it).shortValue() : null); - register(Integer.class, (it)->(it instanceof Number) ? ((Number)it).intValue() : null); - register(Long.class, (it)->(it instanceof Number) ? ((Number)it).longValue() : null); - register(Float.class, (it)->(it instanceof Number) ? ((Number)it).floatValue() : null); - register(Double.class, (it)->(it instanceof Number) ? ((Number)it).doubleValue() : null); - register(Boolean.class, (it)->(it instanceof Boolean) ? (Boolean)it : null); - - register(Void.TYPE, (it)->null); - register(Byte.TYPE, (it)->(it instanceof Number) ? ((Number)it).byteValue() : null); - register(Character.TYPE, (it)->(it instanceof Number) ? (char)((Number)it).shortValue() : it.toString().charAt(0)); - register(Short.TYPE, (it)->(it instanceof Number) ? ((Number)it).shortValue() : null); - register(Integer.TYPE, (it)->(it instanceof Number) ? ((Number)it).intValue() : null); - register(Long.TYPE, (it)->(it instanceof Number) ? ((Number)it).longValue() : null); - register(Float.TYPE, (it)->(it instanceof Number) ? ((Number)it).floatValue() : null); - register(Double.TYPE, (it)->(it instanceof Number) ? ((Number)it).doubleValue() : null); - register(Boolean.TYPE, (it)->(it instanceof Boolean) ? (Boolean)it : null); - - - //registerSerializer(Void.class, (it)->JsonNull.INSTANCE); -// registerSerializer(Character.class, (it)->new JsonPrimitive(""+it)); -// registerSerializer(String.class, JsonPrimitive::new); -// registerSerializer(Byte.class, (it)->new JsonPrimitive(Long.valueOf(it))); -// registerSerializer(Short.class, (it)->new JsonPrimitive(Long.valueOf(it))); -// registerSerializer(Integer.class, (it)->new JsonPrimitive(Long.valueOf(it))); -// registerSerializer(Long.class, JsonPrimitive::new); -// registerSerializer(Float.class, (it)->new JsonPrimitive(Double.valueOf(it))); -// registerSerializer(Double.class, JsonPrimitive::new); -// registerSerializer(Boolean.class, JsonPrimitive::new); - - //registerSerializer(Void.TYPE, (it)->JsonNull.INSTANCE); -// registerSerializer(Character.TYPE, (it)->new JsonPrimitive(""+it)); -// registerSerializer(Byte.TYPE, (it)->new JsonPrimitive(Long.valueOf(it))); -// registerSerializer(Short.TYPE, (it)->new JsonPrimitive(Long.valueOf(it))); -// registerSerializer(Integer.TYPE, (it)->new JsonPrimitive(Long.valueOf(it))); -// registerSerializer(Long.TYPE, JsonPrimitive::new); -// registerSerializer(Float.TYPE, (it)->new JsonPrimitive(Double.valueOf(it))); -// registerSerializer(Double.TYPE, JsonPrimitive::new); -// registerSerializer(Boolean.TYPE, JsonPrimitive::new); - } - - @Override - public E marshall(Type type, DocumentElement elem) throws InstantiationException, MarshallerException, ClassCastException { - //Early shunt into generic collection types - if (type.getClass().isAssignableFrom(List.class)) { - - } else if (type.getClass().isAssignableFrom(Set.class)){ - - } else if (type.getClass().isAssignableFrom(Map.class)) { - - } - - // TODO IMPLEMENT - return null; - } - - /** EXPERIMENTAL. Marshalls elem into a very specific parameterized type, honoring generic type arguments. */ -// @SuppressWarnings("unchecked") -// @Nullable -// public T marshall(Type type, JsonElement elem) { -// if (elem==null) return null; -// //if (elem==JsonNull.INSTANCE) return null; -// -// if (type instanceof Class) { -// try { -// return marshall((Class)type, elem); -// } catch (ClassCastException t) { -// return null; -// } -// } -// -// if (type instanceof ParameterizedType) { -// try { -// Class clazz = (Class) TypeMagic.classForType(type); -// -// return marshall(clazz, elem); -// } catch (ClassCastException t) { -// return null; -// } -// } -// -// return null; -// } -// -// public T marshall(Class clazz, JsonElement elem) { -// try { -// return marshall(clazz, elem, false); -// } catch (Throwable t) { -// return null; -// } -// } - -// public T marshallCarefully(Class clazz, JsonElement elem) throws JsonIOException { -// return marshall(clazz, elem, true); -// } -// -// @SuppressWarnings("unchecked") -// @Nullable -// public T marshall(Class clazz, JsonElement elem, boolean failFast) throws JsonIOException { -// if (elem==null) return null; -// //if (elem==JsonNull.INSTANCE) return null; -// if (clazz.isAssignableFrom(elem.getClass())) return (T)elem; //Already the correct type -// -// //Externally registered deserializers -// DeserializerFunctionPool pool = (DeserializerFunctionPool)deserializers.get(clazz); -// if (pool!=null) { -// try { -// return pool.apply(elem, this); -// } catch (FunctionMatchFailedException e) { -// //Don't return the result, but continue -// } -// } -// -// //Internally annotated deserializers -// pool = POJODeserializer.deserializersFor(clazz); -// T poolResult; -// try { -// poolResult = pool.apply(elem, this); -// return poolResult; -// } catch (FunctionMatchFailedException e) { -// //Don't return the result, but continue -// } -// -// -// if (Enum.class.isAssignableFrom(clazz)) { -// if (!(elem instanceof JsonPrimitive)) return null; -// String name = ((JsonPrimitive)elem).getValue().toString(); -// -// T[] constants = clazz.getEnumConstants(); -// if (constants==null) return null; -// for(T t : constants) { -// if (((Enum)t).name().equals(name)) return t; -// } -// } -// -// if (clazz.equals(String.class)) { -// //Almost everything has a String representation -// if (elem instanceof JsonObject) return (T)((JsonObject)elem).toJson(false, false); -// //if (elem instanceof JsonArray) return (T)((JsonArray)elem).toJson(false, false); -// if (elem instanceof JsonPrimitive) { -// ((JsonPrimitive)elem).getValue(); -// return (T)((JsonPrimitive)elem).asString(); -// } -// //if (elem instanceof JsonNull) return (T)"null"; -// -// if (failFast) throw new JsonIOException("Encountered unexpected JsonElement type while deserializing to string: "+elem.getClass().getCanonicalName()); -// return null; -// } -// -// if (elem instanceof JsonPrimitive) { -// Function func = primitiveMarshallers.get(clazz); -// if (func!=null) { -// return (T)func.apply(((JsonPrimitive)elem).getValue()); -// } else { -// if (failFast) throw new JsonIOException("Don't know how to unpack value '"+elem.toString()+"' into target type '"+clazz.getCanonicalName()+"'"); -// return null; -// } -// } else if (elem instanceof JsonObject) { -// -// -// if (clazz.isPrimitive()) throw new JsonIOException("Can't marshall json object into primitive type "+clazz.getCanonicalName()); -// if (JsonPrimitive.class.isAssignableFrom(clazz)) { -// if (failFast) throw new JsonIOException("Can't marshall json object into a json primitive"); -// return null; -// } -// -// JsonObject obj = (JsonObject) elem; -// obj.setMarshaller(this); -// -// if (typeAdapters.containsKey(clazz)) { -// return (T) typeAdapters.get(clazz).apply((JsonObject) elem); -// } -// -// if (typeFactories.containsKey(clazz)) { -// T result = (T)typeFactories.get(clazz).get(); -// try { -// POJODeserializer.unpackObject(result, obj, failFast); -// return result; -// } catch (Throwable t) { -// if (failFast) throw t; -// return null; -// } -// } else { -// -// try { -// T result = TypeMagic.createAndCast(clazz, failFast); -// POJODeserializer.unpackObject(result, obj, failFast); -// return result; -// } catch (Throwable t) { -// if (failFast) throw t; -// return null; -// } -// } -// -//// } else if (elem instanceof JsonArray) { -//// if (clazz.isPrimitive()) return null; -//// if (clazz.isArray()) { -//// Class componentType = clazz.getComponentType(); -//// JsonArray array = (JsonArray)elem; -//// -//// T result = (T) Array.newInstance(componentType, array.size()); -//// for(int i=0; i serializer = serializers.get(obj.getClass()); -// if (serializer!=null) { -// JsonElement result = serializer.apply(obj, this); -// if (result instanceof JsonObject) ((JsonObject)result).setMarshaller(this); -// //if (result instanceof JsonArray) ((JsonArray)result).setMarshaller(this); -// return result; -// } else { -// //Detailed match -// for(Map.Entry, BiFunction> entry : serializers.entrySet()) { -// if (entry.getKey().isAssignableFrom(obj.getClass())) { -// JsonElement result = entry.getValue().apply(obj, this); -// if (result instanceof JsonObject) ((JsonObject)result).setMarshaller(this); -// //if (result instanceof JsonArray) ((JsonArray)result).setMarshaller(this); -// return result; -// } -// } -// } -// -// //Check for annotations -// for(Method m : obj.getClass().getDeclaredMethods()) { -// if (m.isAnnotationPresent(Serializer.class) && !Modifier.isStatic(m.getModifiers())) { -// Class clazz = m.getReturnType(); -// if (JsonElement.class.isAssignableFrom(clazz)) { -// //This is probably the method we're looking for! Let's figure out its method signature! -// Parameter[] params = m.getParameters(); -// if (params.length==0) { -// try { -// boolean access = m.isAccessible(); -// if (!access) m.setAccessible(true); -// JsonElement result = (JsonElement) m.invoke(obj); -// if (!access) m.setAccessible(false); -// if (result instanceof JsonObject) ((JsonObject)result).setMarshaller(this); -// //if (result instanceof JsonArray) ((JsonArray)result).setMarshaller(this); -// return result; -// } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { -// //return JsonNull.INSTANCE; //TODO: This is a very real and important error case. We need a SerializationException and a way to expose exceptions proactively. -// } -// } else if (params.length==1) { -// if (Marshaller.class.isAssignableFrom(params[0].getType())) { -// try { -// boolean access = m.isAccessible(); -// if (!access) m.setAccessible(true); -// JsonElement result = (JsonElement) m.invoke(obj, this); -// if (!access) m.setAccessible(false); -// if (result instanceof JsonObject) ((JsonObject)result).setMarshaller(this); -// //if (result instanceof JsonArray) ((JsonArray)result).setMarshaller(this); -// return result; -// } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { -// //return JsonNull.INSTANCE; //TODO: Same failure case that needs expressing -// } -// } -// } -// } -// } -// } -// -// if (obj instanceof Enum) { -// return new JsonPrimitive(((Enum)obj).name()); -// } -// /* -// if (obj.getClass().isArray()) { -// -// JsonArray array = new JsonArray(); -// array.setMarshaller(this); -// //Class component = obj.getClass().getComponentType(); -// for(int i=0; i)obj) { -// JsonElement parsed = serialize(elem); -// array.add(parsed); -// } -// return array; -// }*/ -// -// if (obj instanceof Map) { -// JsonObject result = new JsonObject(); -// for(Map.Entry entry : ((Map)obj).entrySet()) { -// String k = entry.getKey().toString(); -// Object v = entry.getValue(); -// result.put(k, serialize(v)); -// } -// return result; -// } -// -// JsonObject result = new JsonObject(); -// //Pull in public fields first -// for(Field f : obj.getClass().getFields()) { -// if ( -// Modifier.isStatic(f.getModifiers()) || // Not part of the object -// Modifier.isTransient(f.getModifiers())) continue; //Never serialize -// f.setAccessible(true); -// -// try { -// Object child = f.get(obj); -// String name = f.getName(); -// SerializedName nameAnnotation = f.getAnnotation(SerializedName.class); -// if (nameAnnotation!=null) name = nameAnnotation.value(); -// -// Comment comment = f.getAnnotation(Comment.class); -// if (comment==null) { -// result.put(name, serialize(child)); -// } else { -// result.put(name, serialize(child), comment.value()); -// } -// } catch (IllegalArgumentException | IllegalAccessException e) {} -// } -// -// //Add in what private fields we can reach -// for (Field f : obj.getClass().getDeclaredFields()) { -// if ( -// Modifier.isPublic(f.getModifiers()) || // Already serialized -// Modifier.isStatic(f.getModifiers()) || // Not part of the object -// Modifier.isTransient(f.getModifiers())) continue; //Never serialize -// f.setAccessible(true); -// -// try { -// Object child = f.get(obj); -// String name = f.getName(); -// SerializedName nameAnnotation = f.getAnnotation(SerializedName.class); -// if (nameAnnotation!=null) name = nameAnnotation.value(); -// -// Comment comment = f.getAnnotation(Comment.class); -// if (comment==null) { -// result.put(name, serialize(child)); -// } else { -// result.put(name, serialize(child), comment.value()); -// } -// } catch (IllegalArgumentException | IllegalAccessException e) {} -// } -// -// return result; -// } -} diff --git a/src/main/java/blue/endless/jankson/impl/POJODeserializer.java b/src/main/java/blue/endless/jankson/impl/POJODeserializer.java deleted file mode 100644 index 1a29c3c..0000000 --- a/src/main/java/blue/endless/jankson/impl/POJODeserializer.java +++ /dev/null @@ -1,295 +0,0 @@ -/* - * 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.impl; - -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.lang.reflect.Parameter; -import java.lang.reflect.ParameterizedType; -import java.lang.reflect.Type; -import java.util.Collection; -import java.util.Map; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -import blue.endless.jankson.api.annotation.Deserializer; -import blue.endless.jankson.api.annotation.SerializedName; -import blue.endless.jankson.api.io.JsonIOException; -import blue.endless.jankson.impl.serializer.InternalDeserializerFunction; -import blue.endless.jankson.impl.serializer.DeserializerFunctionPool; - -public class POJODeserializer { - -// -// public static void unpackObject(Object target, JsonObject source) { -// try { -// unpackObject(target, source, false); -// } catch (Throwable t) { -// } -// } -// -// public static void unpackObject(Object target, JsonObject source, boolean failFast) throws JsonIOException { -// //if (o.getClass().getTypeParameters().length>0) throw new DeserializationException("Can't safely deserialize generic types!"); -// //well, let's try anyway and see if we run into problems. -// -// //Create a copy we can redact keys from -// JsonObject work = source.clone(); -// -// //Fill public and private fields declared in the target object's immediate class -// for(Field f : target.getClass().getDeclaredFields()) { -// int modifiers = f.getModifiers(); -// if (Modifier.isStatic(modifiers) || Modifier.isTransient(modifiers)) continue; -// unpackField(target, f, work, failFast); -// } -// -// //Attempt to fill public, accessible fields declared in the target object's superclass. -// for(Field f : target.getClass().getFields()) { -// int modifiers = f.getModifiers(); -// if (Modifier.isStatic(modifiers) || Modifier.isTransient(modifiers)) continue; -// unpackField(target, f, work, failFast); -// } -// -// if (!work.isEmpty() && failFast) { -// throw new JsonIOException("There was data that couldn't be applied to the destination object: "+work.toJson(JsonGrammar.STRICT)); -// } -// } -// -// public static void unpackField(Object parent, Field f, JsonObject source, boolean failFast) throws JsonIOException { -// String fieldName = f.getName(); -// SerializedName nameAnnotation = f.getAnnotation(SerializedName.class); -// if (nameAnnotation!=null) fieldName = nameAnnotation.value(); -// -// if (source.containsKey(fieldName)) { -// JsonElement elem = source.get(fieldName); -// source.remove(fieldName); //Prevent it from getting re-unpacked -//// if (elem==null || elem==JsonNull.INSTANCE) { -//// boolean accessible = f.isAccessible(); -//// if (!accessible) f.setAccessible(true); -//// try { -//// f.set(parent, null); -//// if (!accessible) f.setAccessible(false); -//// } catch (IllegalArgumentException | IllegalAccessException ex) { -//// if (failFast) throw new JsonIOException("Couldn't set field \""+f.getName()+"\" of class \""+parent.getClass().getCanonicalName()+"\"", ex); -//// } -//// } else { -// try { -// unpackFieldData(parent, f, elem, source.getMarshaller()); -// } catch (Throwable t) { -// if (failFast) throw new JsonIOException("There was a problem unpacking field "+f.getName()+" of class "+parent.getClass().getCanonicalName(), t); -// } -//// } -// } -// } -// -// -// /** NOT WORKING YET, HIGHLY EXPERIMENTAL */ -// @Nullable -// public static Object unpack(Type t, JsonElement elem, blue.endless.jankson.api.Marshaller marshaller) { -// Class rawClass = TypeMagic.classForType(t); -// if (rawClass.isPrimitive()) return null; //We can't unpack a primitive into an object of primitive type. Maybe in the future we can return a boxed type? -// -// if (elem==null) return null; -// /* -// if (type instanceof Class) { -// try { -// return marshaller.marshall((Class) type, elem); -// } catch (ClassCastException t) { -// return null; -// } -// } -// -// if (type instanceof ParameterizedType) { -// try { -// Class clazz = (Class) TypeMagic.classForType(type); -// -// if (List.class.isAssignableFrom(clazz)) { -// Object result = TypeMagic.createAndCast(type); -// -// try { -// unpackList((List) result, type, elem, marshaller); -// return result; -// } catch (DeserializationException e) { -// e.printStackTrace(); -// return result; -// } -// } -// -// return null; -// } catch (ClassCastException t) { -// return null; -// } -// }*/ -// -// return null; -// } -// -// @SuppressWarnings("unchecked") -// public static boolean unpackFieldData(Object parent, Field field, JsonElement elem, blue.endless.jankson.api.Marshaller marshaller) throws Throwable { -// -// if (elem==null) return true; -// try { -// field.setAccessible(true); -// } catch (Throwable t) { -// return false; //skip this field probably. -// } -// -// //if (elem==JsonNull.INSTANCE) { -// // field.set(parent, null); -// // return true; -// //} -// -// Class fieldClass = field.getType(); -// -// if (!isCollections(fieldClass)) { -// //Try to directly marshall -// Object result = marshaller.marshallCarefully(fieldClass, elem); -// field.set(parent, result); -// return true; -// } -// -// -// if (field.get(parent)==null) { -// Object fieldValue = TypeMagic.createAndCast(field.getGenericType()); -// -// if (fieldValue==null) { -// return false; //Can't deserialize this somehow -// } else { -// field.set(parent, fieldValue); -// } -// } -// -// if (Map.class.isAssignableFrom(fieldClass)) { -// Type[] parameters = ((ParameterizedType)field.getGenericType()).getActualTypeArguments(); -// -// unpackMap((Map) field.get(parent), parameters[0], parameters[1], elem, marshaller); -// -// return true; -// } -// -// if (Collection.class.isAssignableFrom(fieldClass)) { -// Type elementType = ((ParameterizedType)field.getGenericType()).getActualTypeArguments()[0]; -// -// unpackCollection((Collection)field.get(parent), elementType, elem, marshaller); -// -// return true; -// } -// -// return false; -// } -// -// private static boolean isCollections(Class clazz) { -// return -// Map.class.isAssignableFrom(clazz) || -// Collection.class.isAssignableFrom(clazz); -// } -// -// public static void unpackMap(Map map, Type keyType, Type valueType, JsonElement elem, blue.endless.jankson.api.Marshaller marshaller) throws JsonIOException { -// if (!(elem instanceof JsonObject)) throw new JsonIOException("Cannot deserialize a "+elem.getClass().getSimpleName()+" into a Map - expected a JsonObject!"); -// -// //Class keyClass = TypeMagic.classForType(keyType); -// //Class valueClass = TypeMagic.classForType(valueType); -// JsonObject object = (JsonObject)elem; -// for(Map.Entry entry : object.entrySet()) { -// try { -// Object k = marshaller.marshall(keyType, new JsonPrimitive(entry.getKey())); -// Object v = marshaller.marshall(valueType, entry.getValue()); -// if (k!=null && v!=null) map.put(k, v); -// } catch (Throwable t) {} -// } -// } -// -// public static void unpackCollection(Collection collection, Type elementType, JsonElement elem, blue.endless.jankson.api.Marshaller marshaller) throws JsonIOException { -// /* -// if (!(elem instanceof JsonArray)) throw new JsonIOException("Cannot deserialize a "+elem.getClass().getSimpleName()+" into a Set - expected a JsonArray!"); -// -// JsonArray array = (JsonArray)elem; -// for(JsonElement arrayElem : array) { -// -// Object o = marshaller.marshall(elementType, arrayElem); -// if (o!=null) collection.add(o); -// }*/ -// } -// -// protected static DeserializerFunctionPool deserializersFor(Class targetClass) { -// DeserializerFunctionPool pool = new DeserializerFunctionPool<>(targetClass); -// for(Method m: targetClass.getDeclaredMethods()) { -// //System.out.println("Examining "+m.getName()); -// if (m.getAnnotation(Deserializer.class)==null) continue; //Must be annotated -// -// if (!Modifier.isStatic(m.getModifiers())) continue; //Must be static -// if (!m.getReturnType().equals(targetClass)) continue; //Must return an instance of the class -// //System.out.println(" Cleared first screening"); -// Parameter[] params = m.getParameters(); -// if (params.length>=1) { -// Class sourceClass = params[0].getType(); -// InternalDeserializerFunction deserializer = makeDeserializer(m, sourceClass, targetClass); -// if (deserializer==null) continue; -// pool.registerUnsafe(sourceClass, deserializer); -// //System.out.println(" Registered deserializer"); -// } -// } -// return pool; -// } -// -// /** Assuming the method is a valid deserializer, and matches the type signature required, produces a DeserializerFunction which delegates to the method provided. -// * If the method is not a valid deserializer of this type, returns null instead. -// */ -// @SuppressWarnings("unchecked") -// @Nullable -// private static InternalDeserializerFunction makeDeserializer(@Nonnull Method m, @Nonnull Class sourceClass, @Nonnull Class targetClass) { -// if (!m.getReturnType().equals(targetClass)) return null; -// Parameter[] params = m.getParameters(); -// if (params.length==1) { -// //if (params[0].getClass().isAssignableFrom(sourceClass)) { -// return (Object o, blue.endless.jankson.api.Marshaller marshaller)->{ -// try { -// return (B)m.invoke(null, o); -// } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) { -// throw new JsonIOException(ex); -// } -// }; -// //} -// //return null; -// } else if (params.length==2) { -// //if (params[0].getClass().isAssignableFrom(sourceClass)) { -// if (params[1].getType().equals(blue.endless.jankson.api.Marshaller.class)) { -// return (Object o, blue.endless.jankson.api.Marshaller marshaller)->{ -// try { -// return (B)m.invoke(null, o, marshaller); -// } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) { -// throw new JsonIOException(ex); -// } -// }; -// } -// //} -// return null; -// } else { -// return null; -// } -// } -} diff --git a/src/main/java/blue/endless/jankson/impl/io/AbstractStructuredDataReader.java b/src/main/java/blue/endless/jankson/impl/io/AbstractStructuredDataReader.java index 70cd805..3f6d67e 100644 --- a/src/main/java/blue/endless/jankson/impl/io/AbstractStructuredDataReader.java +++ b/src/main/java/blue/endless/jankson/impl/io/AbstractStructuredDataReader.java @@ -35,7 +35,7 @@ public abstract class AbstractStructuredDataReader implements StructuredDataReader { protected final LookaheadCodePointReader src; - protected final StructuredDataPipe readQueue = new StructuredDataPipe(); + protected final StructuredDataBuffer readQueue = new StructuredDataBuffer(); private final Deque contextStack = new ArrayDeque<>(); public AbstractStructuredDataReader(Reader src) { diff --git a/src/main/java/blue/endless/jankson/impl/io/StructuredDataPipe.java b/src/main/java/blue/endless/jankson/impl/io/StructuredDataBuffer.java similarity index 93% rename from src/main/java/blue/endless/jankson/impl/io/StructuredDataPipe.java rename to src/main/java/blue/endless/jankson/impl/io/StructuredDataBuffer.java index 40eb1f9..2ff0294 100644 --- a/src/main/java/blue/endless/jankson/impl/io/StructuredDataPipe.java +++ b/src/main/java/blue/endless/jankson/impl/io/StructuredDataBuffer.java @@ -24,7 +24,6 @@ package blue.endless.jankson.impl.io; -import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.Optional; @@ -37,7 +36,7 @@ * A FIFO queue / buffer that acts as both a reader and a writer, such that data written will be * later visible on reads. */ -public class StructuredDataPipe implements StructuredDataWriter, StructuredDataReader { +public class StructuredDataBuffer implements StructuredDataWriter, StructuredDataReader { private Deque data = new ArrayDeque<>(); /** @@ -95,14 +94,14 @@ public void push(StructuredData value) { // implements StructuredDataWriter { @Override - public void write(StructuredData value) throws IOException { + public void write(StructuredData value) { data.addLast(value); } // } // implements StructuredDataReader { @Override - public StructuredData next() throws IOException { + public StructuredData next() { if (data.isEmpty()) return StructuredData.EOF; return data.removeFirst(); } diff --git a/src/main/java/blue/endless/jankson/impl/io/objectreader/ArrayStructuredDataReader.java b/src/main/java/blue/endless/jankson/impl/io/objectreader/ArrayStructuredDataReader.java index 28213c2..6a6a662 100644 --- a/src/main/java/blue/endless/jankson/impl/io/objectreader/ArrayStructuredDataReader.java +++ b/src/main/java/blue/endless/jankson/impl/io/objectreader/ArrayStructuredDataReader.java @@ -37,14 +37,14 @@ public ArrayStructuredDataReader(Object array) { if (!array.getClass().isArray()) throw new IllegalArgumentException("This class can only be used with arrays."); this.arr = array; - prebuffer(StructuredData.ARRAY_START); + buffer(StructuredData.ARRAY_START); } @Override protected void onDelegateEmpty() { if (index >= Array.getLength(arr)) { - prebuffer(StructuredData.ARRAY_END); - prebuffer(StructuredData.EOF); + buffer(StructuredData.ARRAY_END); + buffer(StructuredData.EOF); } else { Object o = Array.get(arr, index); index++; diff --git a/src/main/java/blue/endless/jankson/impl/io/objectreader/CollectionStructuredDataReader.java b/src/main/java/blue/endless/jankson/impl/io/objectreader/CollectionStructuredDataReader.java index b86fffa..9f12264 100644 --- a/src/main/java/blue/endless/jankson/impl/io/objectreader/CollectionStructuredDataReader.java +++ b/src/main/java/blue/endless/jankson/impl/io/objectreader/CollectionStructuredDataReader.java @@ -34,14 +34,14 @@ public class CollectionStructuredDataReader extends DelegatingStructuredDataRead public CollectionStructuredDataReader(Collection collection) { iter = collection.iterator(); - prebuffer(StructuredData.ARRAY_START); + buffer(StructuredData.ARRAY_START); } @Override protected void onDelegateEmpty() { if (!iter.hasNext()) { - prebuffer(StructuredData.ARRAY_END); - prebuffer(StructuredData.EOF); + buffer(StructuredData.ARRAY_END); + buffer(StructuredData.EOF); } else { this.setDelegate(ObjectStructuredDataReader.of(iter.next())); } diff --git a/src/main/java/blue/endless/jankson/impl/io/objectreader/DelegatingStructuredDataReader.java b/src/main/java/blue/endless/jankson/impl/io/objectreader/DelegatingStructuredDataReader.java index a3e329c..6a09efa 100644 --- a/src/main/java/blue/endless/jankson/impl/io/objectreader/DelegatingStructuredDataReader.java +++ b/src/main/java/blue/endless/jankson/impl/io/objectreader/DelegatingStructuredDataReader.java @@ -28,35 +28,35 @@ import blue.endless.jankson.api.io.StructuredData; import blue.endless.jankson.api.io.StructuredDataReader; -import blue.endless.jankson.impl.io.StructuredDataPipe; +import blue.endless.jankson.impl.io.StructuredDataBuffer; public abstract class DelegatingStructuredDataReader implements StructuredDataReader { private StructuredDataReader delegate = null; - private final StructuredDataPipe pipe = new StructuredDataPipe(); + private final StructuredDataBuffer buffer = new StructuredDataBuffer(); private StructuredData latestEntry = null; @Override public boolean hasNext() { - boolean emptyPipe = pipe.isEmpty(); + boolean emptyBuffer = buffer.isEmpty(); boolean emptyDelegate = delegate == null || !delegate.hasNext(); // Technically this is an illegal scenario, but we SHOULD have thrown by now. - if (emptyPipe && emptyDelegate) return false; + if (emptyBuffer && emptyDelegate) return false; // If the pipe is non-empty and the next entry is not EOF, we're ready for reading. - return !emptyPipe && pipe.peek().type() != StructuredData.Type.EOF; + return !emptyBuffer && buffer.peek().type() != StructuredData.Type.EOF; } @Override public StructuredData next() throws IOException { - if (pipe.isEmpty()) { + if (buffer.isEmpty()) { //Usually this will happen on the first run. Prime our first element loadNextElem(); } - boolean eof = pipe.isEof(); + boolean eof = buffer.isEof(); // loadNextElem guarantees !pipe.isEmpty() - latestEntry = pipe.pop(); + latestEntry = buffer.pop(); // If we're not at EOF, load the next item so we always have an answer for hasNext if (!eof) loadNextElem(); @@ -68,8 +68,8 @@ public StructuredData next() throws IOException { * Buffers an element so that it will be presented next, after any previously buffered data * @param value the value to buffer */ - protected void prebuffer(StructuredData value) { - pipe.push(value); + protected void buffer(StructuredData value) { + buffer.push(value); } protected void setDelegate(StructuredDataReader reader) { @@ -86,7 +86,7 @@ protected void setDelegate(StructuredDataReader reader) { */ private void loadNextElem() throws IOException { // If we're already fulfilled, NOP out. - if (!pipe.isEmpty()) return; + if (!buffer.isEmpty()) return; if (delegate == null || !delegate.hasNext()) { // We have absolutely no data available. Clear out the delegate if present and call onDelegateEmpty to prime some data @@ -94,19 +94,19 @@ private void loadNextElem() throws IOException { delegate = null; onDelegateEmpty(); - if (!pipe.isEmpty()) return; // Neat, data was primed directly! + if (!buffer.isEmpty()) return; // Neat, data was primed directly! // No data was directly primed, so we NEED a delegate to continue operating properly. if (delegate == null || !delegate.hasNext()) throw new IllegalStateException("No new data was made available from onDelegateEmpty()!"); // We're all set to fill the pipe ourselves - pipe.push(delegate.next()); + buffer.push(delegate.next()); //Not *needed* but helps things short circuit faster if (!delegate.hasNext()) { delegate = null; } } else { // There's already a delegate, fill the pipe - pipe.push(delegate.next()); + buffer.push(delegate.next()); //Not *needed* but helps things short circuit faster if (!delegate.hasNext()) { delegate = null; diff --git a/src/main/java/blue/endless/jankson/impl/io/objectreader/MapStructuredDataReader.java b/src/main/java/blue/endless/jankson/impl/io/objectreader/MapStructuredDataReader.java index 50db2cd..3ce434d 100644 --- a/src/main/java/blue/endless/jankson/impl/io/objectreader/MapStructuredDataReader.java +++ b/src/main/java/blue/endless/jankson/impl/io/objectreader/MapStructuredDataReader.java @@ -40,19 +40,19 @@ public MapStructuredDataReader(Map map) { this.map = (Map) map; this.iterator = this.map.entrySet().iterator(); - this.prebuffer(StructuredData.OBJECT_START); + this.buffer(StructuredData.OBJECT_START); } @Override protected void onDelegateEmpty() throws IOException { if (!iterator.hasNext()) { - prebuffer(StructuredData.OBJECT_END); - prebuffer(StructuredData.EOF); + buffer(StructuredData.OBJECT_END); + buffer(StructuredData.EOF); return; } Map.Entry entry = iterator.next(); - prebuffer(StructuredData.objectKey( + buffer(StructuredData.objectKey( Objects.toString(entry.getKey()) )); setDelegate(ObjectStructuredDataReader.of(entry.getValue())); diff --git a/src/main/java/blue/endless/jankson/impl/io/objectreader/ObjectStructuredDataReader.java b/src/main/java/blue/endless/jankson/impl/io/objectreader/ObjectStructuredDataReader.java index 09dd8ba..cf3d180 100644 --- a/src/main/java/blue/endless/jankson/impl/io/objectreader/ObjectStructuredDataReader.java +++ b/src/main/java/blue/endless/jankson/impl/io/objectreader/ObjectStructuredDataReader.java @@ -50,7 +50,7 @@ public class ObjectStructuredDataReader extends DelegatingStructuredDataReader { private ObjectStructuredDataReader(Object object) { this.obj = object; - this.prebuffer(StructuredData.OBJECT_START); + this.buffer(StructuredData.OBJECT_START); Set alreadyTaken = new HashSet<>(); for(Field f : obj.getClass().getDeclaredFields()) { @@ -68,8 +68,8 @@ private ObjectStructuredDataReader(Object object) { @Override protected void onDelegateEmpty() throws IOException { if (pendingFields.isEmpty()) { - prebuffer(StructuredData.OBJECT_END); - prebuffer(StructuredData.EOF); + buffer(StructuredData.OBJECT_END); + buffer(StructuredData.EOF); return; } @@ -77,11 +77,11 @@ protected void onDelegateEmpty() throws IOException { String fieldName = cur.getName(); SerializedName[] serializedNames = cur.getDeclaredAnnotationsByType(SerializedName.class); if (serializedNames.length > 0) fieldName = serializedNames[0].value(); - prebuffer(StructuredData.objectKey(fieldName)); + buffer(StructuredData.objectKey(fieldName)); try { Object value = TypeMagic.getFieldValue(cur, obj); if (value == null) { - prebuffer(StructuredData.NULL); + buffer(StructuredData.NULL); } else { setDelegate(ObjectStructuredDataReader.of(value)); } diff --git a/src/main/java/blue/endless/jankson/impl/serializer/CommentSerializer.java b/src/main/java/blue/endless/jankson/impl/serializer/CommentSerializer.java deleted file mode 100644 index fe219ac..0000000 --- a/src/main/java/blue/endless/jankson/impl/serializer/CommentSerializer.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * 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.impl.serializer; - -import java.io.IOException; -import java.io.Writer; - -import blue.endless.jankson.api.io.JsonWriterOptions; - -public class CommentSerializer { - - public static void print(Writer writer, String comment, int indent, JsonWriterOptions grammar) throws IOException { - if (comment==null || comment.trim().isEmpty()) return; - StringBuilder b = new StringBuilder(comment.length()); - print(b, comment, indent, grammar); - writer.append(b); - } - - public static void print(StringBuilder builder, String comment, int indent, JsonWriterOptions grammar) { - boolean comments = grammar.get(JsonWriterOptions.Hint.WRITE_COMMENTS); - boolean whitespace = grammar.get(JsonWriterOptions.Hint.WRITE_WHITESPACE); - print(builder, comment, indent, comments, whitespace); - } - - // Note: Indent may be -1. - public static void print(StringBuilder builder, String comment, int indent, boolean comments, boolean whitespace) { - if (!comments) return; - if (comment==null || comment.trim().isEmpty()) return; - - if (whitespace) { - if (comment.contains("\n")) { - //Use /* */ comment - builder.append("/* "); - String[] lines = comment.split("\\n"); - for(int i=0; i { - private Class targetClass; - private HashMap, InternalDeserializerFunction> values = new HashMap<>(); - - public DeserializerFunctionPool(Class targetClass) { - this.targetClass = targetClass; - } - - public void registerUnsafe(Class sourceClass, InternalDeserializerFunction function) { - values.put(sourceClass, function); - } - - public InternalDeserializerFunction getFunction(Class sourceClass) { - return (InternalDeserializerFunction)values.get(sourceClass); - } - - //public B apply(JsonElement elem, Marshaller marshaller) throws JsonIOException, FunctionMatchFailedException { - // return null; - /* - InternalDeserializerFunction selected = null; - - //This whole block is pretty ugly but there's a very particular selection order - if (elem instanceof JsonPrimitive) { - //1. Unwrapped primitive class - Object obj = ((JsonPrimitive) elem).getValue(); - selected = values.get(obj.getClass()); - if (selected!=null) return selected.deserialize(obj, marshaller); - - //2. JsonPrimitive - selected = values.get(JsonPrimitive.class); - if (selected!=null) return selected.deserialize((JsonPrimitive)elem, marshaller); - } else if (elem instanceof JsonObject) { - //2. JsonObject - selected = values.get(JsonObject.class); - if (selected!=null) return selected.deserialize((JsonObject)elem, marshaller); - } else if (elem instanceof JsonArray) { - //2. JsonArray - selected = values.get(JsonArray.class); - if (selected!=null) return selected.deserialize((JsonArray)elem, marshaller); - } - - //3. JsonElement - selected = values.get(JsonElement.class); - if (selected!=null) return selected.deserialize((JsonElement)elem, marshaller); - - //We can't just return null, *because null might be the intended output of one of the functions above!* - throw new FunctionMatchFailedException("Couldn't find a deserializer in class '"+targetClass.getCanonicalName()+"' to unpack element '"+elem.toJson(JsonGrammar.JSON5)+"'."); - */ - //} - - public static class FunctionMatchFailedException extends Exception { - private static final long serialVersionUID = -7909332778483440658L; - public FunctionMatchFailedException(String message) { super(message); } - } -}