diff --git a/.idea/modules/opack.main.iml b/.idea/modules/opack.main.iml index bb1310d..026e800 100644 --- a/.idea/modules/opack.main.iml +++ b/.idea/modules/opack.main.iml @@ -1,5 +1,5 @@ - + diff --git a/.idea/modules/opack.test.iml b/.idea/modules/opack.test.iml index 540b312..9dc5ce5 100644 --- a/.idea/modules/opack.test.iml +++ b/.idea/modules/opack.test.iml @@ -1,5 +1,5 @@ - + diff --git a/.idea/opack.iml b/.idea/opack.iml index f98ca47..61f99bb 100644 --- a/.idea/opack.iml +++ b/.idea/opack.iml @@ -1,5 +1,5 @@ - + diff --git a/README.md b/README.md index 02c44af..b2c5e72 100644 --- a/README.md +++ b/README.md @@ -44,11 +44,14 @@ OpackValue opackValue = opacker.serialize(someObject); #### 2. Deserialize ```java Opacker opacker = new Opacker.Builder() - .setContextStackInitialSize(128) // (Optional) Creation size of stack for processing - .setValueStackInitialSize(512) // (Optional) Creation size of stack for processing - .setConvertEnumToOrdinal(false) // (Optional) Convert Enum to ordinal or name - .setEnableWrapListElementType(false) // (Optional) When converting elements of a list, record the type as well - .setEnableWrapMapElementType(false) // (Optional) When converting elements of a map, record the type as well + .setContextStackInitialSize(128) // (Optional) Creation size of stack for processing + .setValueStackInitialSize(512) // (Optional) Creation size of stack for processing + + .setEnableWrapListElementType(false) // (Optional) When converting elements of a list, record the type as well + .setEnableWrapMapElementType(false) // (Optional) When converting elements of a map, record the type as well + .setEnableConvertEnumToOrdinal(false) // (Optional) Convert enum to ordinal or name + .setEnableConvertRecursiveDependencyToNull(false); // (Optional) Convert recursive depandency, record null + .create(); OpackValue serializedSomeObject = /** See Serialize Usage **/; @@ -59,11 +62,14 @@ SomeObject someObject = opacker.deserialize(SomeObject.class, serializedSomeObje #### 3. Json Codec ```java JsonCodec jsonCodec = new JsonCodec.Builder() - .setEncodeStackInitialSize(128) // (Optional) Creation size of stack for processing - .setEncodeStringBufferSize(1024) // (Optional) Creation size of stack for processing - .setDecodeStackInitialSize(128) // (Optional) Creation size of stack for processing - .setAllowOpackValueToKeyValue(false) // (Optional) Accepts Objct or Array as Key of Json Object - .setPrettyFormat(false) // (Optional) When encoding, it prints formatted + .setEncodeStackInitialSize(128) // (Optional) Creation size of stack for processing + .setEncodeStringBufferSize(1024) // (Optional) Creation size of stack for processing + .setDecodeStackInitialSize(128) // (Optional) Creation size of stack for processing + + .setAllowOpackValueToKeyValue(false) // (Optional) Accepts Objct or Array as Key of Json Object + .setEnableConvertCharacterToString(false) // (Optional) Convert character to string instead of character int value + .setUsePrettyFormat(false) // (Optional) When encoding, it prints formatted + .create(); OpackValue opackValue = /** See Serialize Usage **/; @@ -85,10 +91,12 @@ OpackValue decodedOpackValue = jsonCodec.decode(json); #### 4. Dense Codec ```java DenseCodec denseCodec = new DenseCodec.Builder() - .setDecodeStackInitialSize(128) // (Optional) Creation size of stack for processing - .setEncodeStackInitialSize(128) // (Optional) Creation size of stack for processing - .setEncodeOutputBufferInitialSize(1024) // (Optional) Creation size of stack for processing - .setIgnoreVersionCompare(false) // (Optional) Ignore compare dense codec version in data + .setEncodeStackInitialSize(128) // (Optional) Creation size of stack for processing + .setEncodeOutputBufferInitialSize(1024) // (Optional) Creation size of stack for processing + .setDecodeStackInitialSize(128) // (Optional) Creation size of stack for processing + + .setIgnoreVersionCompare(false) // (Optional) Ignore compare dense codec version in data + .create(); OpackValue opackValue = /** See Serialize Usage **/; diff --git a/build.gradle b/build.gradle index ddf0cba..5ea4e64 100644 --- a/build.gradle +++ b/build.gradle @@ -27,7 +27,7 @@ plugins { group 'com.realtimetech' archivesBaseName = "opack" -version = "0.0.7" +version = "0.0.8" compileJava.options.encoding = 'UTF-8' diff --git a/src/main/java/com/realtimetech/opack/Opacker.java b/src/main/java/com/realtimetech/opack/Opacker.java index 040b410..1461a91 100644 --- a/src/main/java/com/realtimetech/opack/Opacker.java +++ b/src/main/java/com/realtimetech/opack/Opacker.java @@ -42,6 +42,7 @@ import java.lang.reflect.Array; import java.lang.reflect.InvocationTargetException; +import java.util.HashSet; import java.util.List; import java.util.Map; @@ -52,8 +53,8 @@ public static class Builder { boolean enableWrapListElementType; boolean enableWrapMapElementType; - - boolean convertEnumToOrdinal; + boolean enableConvertEnumToOrdinal; + boolean enableConvertRecursiveDependencyToNull; public Builder() { this.valueStackInitialSize = 512; @@ -61,8 +62,8 @@ public Builder() { this.enableWrapListElementType = false; this.enableWrapMapElementType = false; - - this.convertEnumToOrdinal = false; + this.enableConvertEnumToOrdinal = false; + this.enableConvertRecursiveDependencyToNull = false; } public Builder setValueStackInitialSize(int valueStackInitialSize) { @@ -85,8 +86,13 @@ public Builder setEnableWrapMapElementType(boolean enableWrapMapElementType) { return this; } - public Builder setConvertEnumToOrdinal(boolean convertEnumToOrdinal) { - this.convertEnumToOrdinal = convertEnumToOrdinal; + public Builder setEnableConvertEnumToOrdinal(boolean enableConvertEnumToOrdinal) { + this.enableConvertEnumToOrdinal = enableConvertEnumToOrdinal; + return this; + } + + public Builder setEnableConvertRecursiveDependencyToNull(boolean enableConvertRecursiveDependencyToNull) { + this.enableConvertRecursiveDependencyToNull = enableConvertRecursiveDependencyToNull; return this; } @@ -109,8 +115,10 @@ public enum State { final @NotNull FastStack objectStack; final @NotNull FastStack typeStack; final @NotNull FastStack valueStack; + final @NotNull HashSet overlapSet; - final boolean convertEnumToOrdinal; + final boolean enableConvertEnumToOrdinal; + final boolean enableConvertRecursiveDependencyToNull; @NotNull State state; @@ -126,7 +134,7 @@ public enum State { this.objectStack = new FastStack<>(builder.contextStackInitialSize); this.typeStack = new FastStack<>(builder.contextStackInitialSize); this.valueStack = new FastStack<>(builder.valueStackInitialSize); - + this.overlapSet = new HashSet<>(); this.state = State.NONE; try { @@ -145,7 +153,8 @@ public enum State { throw new IllegalStateException(exception); } - this.convertEnumToOrdinal = builder.convertEnumToOrdinal; + this.enableConvertEnumToOrdinal = builder.enableConvertEnumToOrdinal; + this.enableConvertRecursiveDependencyToNull = builder.enableConvertRecursiveDependencyToNull; } /** @@ -157,7 +166,11 @@ public enum State { */ public synchronized OpackValue serialize(Object object) throws SerializeException { if (this.state == State.DESERIALIZE) - throw new SerializeException("Opacker is deserializing"); + throw new SerializeException("Opacker is deserializing."); + + if (this.state == State.NONE) { + this.overlapSet.clear(); + } int separatorStack = this.objectStack.getSize(); OpackValue value = (OpackValue) this.prepareObjectSerialize(object.getClass(), object.getClass(), object); @@ -216,7 +229,7 @@ Object prepareObjectSerialize(Class baseType, Class originalType, Object o Enum converting */ if (objectType.isEnum()) { - if (this.convertEnumToOrdinal) { + if (this.enableConvertEnumToOrdinal) { Object[] enums = objectType.getEnumConstants(); for (int i = 0; i < enums.length; i++) { @@ -250,13 +263,22 @@ Object prepareObjectSerialize(Class baseType, Class originalType, Object o opackValue = new OpackObject<>(); } + if (this.overlapSet.contains(object)) { + if (!this.enableConvertRecursiveDependencyToNull) { + throw new SerializeException("Recursive dependencies are not serializable."); + } + + return null; + } + + this.overlapSet.add(object); this.objectStack.push(object); this.valueStack.push(opackValue); this.typeStack.push(bakedType); return opackValue; } catch (BakeException exception) { - throw new SerializeException("Can't bake " + baseType.getName() + " class information", exception); + throw new SerializeException("Can't bake " + baseType.getName() + " class information.", exception); } } @@ -299,7 +321,7 @@ void executeSerializeStack(int endOfStack) throws SerializeException { Object serializedValue = this.prepareObjectSerialize(fieldType, originalType, element); opackObject.put(property.getName(), serializedValue); } catch (IllegalAccessException exception) { - throw new SerializeException("Can't get " + property.getName() + " field data in " + bakedType.getType().getSimpleName(), exception); + throw new SerializeException("Can't get " + property.getName() + " field data in " + bakedType.getType().getSimpleName() + ".", exception); } } } @@ -316,7 +338,11 @@ void executeSerializeStack(int endOfStack) throws SerializeException { */ public synchronized T deserialize(Class type, OpackValue opackValue) throws DeserializeException { if (this.state == State.SERIALIZE) - throw new DeserializeException("Opacker is serializing"); + throw new DeserializeException("Opacker is serializing."); + + if (this.state == State.NONE) { + this.overlapSet.clear(); + } int separatorStack = this.objectStack.getSize(); T value = type.cast(this.prepareObjectDeserialize(type, opackValue)); @@ -369,7 +395,7 @@ public synchronized Object prepareObjectDeserialize(Class goalType, Object ob Enum converting */ if (goalType.isEnum()) { - if (this.convertEnumToOrdinal) { + if (this.enableConvertEnumToOrdinal) { return goalType.getEnumConstants()[(int) ReflectionUtil.cast(Integer.class, object)]; } else { return Enum.valueOf((Class) goalType, object.toString()); @@ -389,7 +415,7 @@ public synchronized Object prepareObjectDeserialize(Class goalType, Object ob try { return OpackArrayConverter.convertToArray(componentType, opackArray); } catch (InvocationTargetException | IllegalAccessException exception) { - throw new DeserializeException("Can't convert OpackArray to native array", exception); + throw new DeserializeException("Can't convert OpackArray to native array.", exception); } } } @@ -405,7 +431,7 @@ public synchronized Object prepareObjectDeserialize(Class goalType, Object ob targetObject = Array.newInstance(goalType.getComponentType(), opackArray.length()); } else { - throw new DeserializeException("Target class is array. but, object is not OpackArray"); + throw new DeserializeException("Target class is array. but, object is not OpackArray."); } } else { if (object instanceof OpackObject) { @@ -414,10 +440,10 @@ public synchronized Object prepareObjectDeserialize(Class goalType, Object ob try { targetObject = ReflectionUtil.createInstanceUnsafe(goalType); } catch (InvocationTargetException | IllegalAccessException | InstantiationException exception) { - throw new DeserializeException("Can't create instance using unsafe method", exception); + throw new DeserializeException("Can't create instance using unsafe method.", exception); } } else { - throw new DeserializeException("Target class is object. but, object is not OpackObject"); + throw new DeserializeException("Target class is object. but, object is not OpackObject."); } } @@ -429,10 +455,10 @@ public synchronized Object prepareObjectDeserialize(Class goalType, Object ob } else if (object.getClass() == goalType) { return object; } else { - throw new DeserializeException("Found object, stack corruption"); + throw new DeserializeException("Found object, stack corruption."); } } catch (BakeException exception) { - throw new DeserializeException("Can't bake " + goalType.getName() + " class information", exception); + throw new DeserializeException("Can't bake " + goalType.getName() + " class information.", exception); } } @@ -474,7 +500,7 @@ void executeDeserializeStack(int endOfStack) throws DeserializeException { property.set(object, deserializedValue == null ? null : ReflectionUtil.cast(actualFieldType, deserializedValue)); } catch (IllegalAccessException | IllegalArgumentException exception) { - throw new DeserializeException("Can't set " + property.getName() + " field in " + bakedType.getType().getSimpleName(), exception); + throw new DeserializeException("Can't set " + property.getName() + " field in " + bakedType.getType().getSimpleName() + ".", exception); } } } diff --git a/src/main/java/com/realtimetech/opack/codec/dense/DenseCodec.java b/src/main/java/com/realtimetech/opack/codec/dense/DenseCodec.java index 80d6972..46080da 100644 --- a/src/main/java/com/realtimetech/opack/codec/dense/DenseCodec.java +++ b/src/main/java/com/realtimetech/opack/codec/dense/DenseCodec.java @@ -44,6 +44,7 @@ public final static class Builder { int encodeOutputBufferInitialSize; int encodeStackInitialSize; int decodeStackInitialSize; + boolean ignoreVersionCompare; public Builder() { @@ -365,7 +366,7 @@ protected void doEncode(OutputStream outputStream, OpackValue opackValue) throws } } } catch (InvocationTargetException | IllegalAccessException e) { - throw new IllegalStateException("Failed to access the native list object in OpackArray"); + throw new IllegalStateException("Failed to access the native list object in OpackArray."); } } else { if (objectType == boolean.class) { @@ -400,7 +401,7 @@ protected void doEncode(OutputStream outputStream, OpackValue opackValue) throws denseWriter.writeInt(bytes.length); denseWriter.writeBytes(bytes); } else { - throw new IllegalArgumentException(objectType + " is not allowed in dense format. (unknown literal object type)"); + throw new IllegalArgumentException(objectType + " is not allowed in dense format. (unknown literal object type)."); } } } diff --git a/src/main/java/com/realtimetech/opack/codec/json/JsonCodec.java b/src/main/java/com/realtimetech/opack/codec/json/JsonCodec.java index cdae145..2e3521b 100644 --- a/src/main/java/com/realtimetech/opack/codec/json/JsonCodec.java +++ b/src/main/java/com/realtimetech/opack/codec/json/JsonCodec.java @@ -36,34 +36,24 @@ public final class JsonCodec extends OpackCodec { public final static class Builder { - boolean allowOpackValueToKeyValue; - boolean convertCharacterToString; - boolean prettyFormat; - int encodeStackInitialSize; int encodeStringBufferSize; int decodeStackInitialSize; + boolean allowOpackValueToKeyValue; + boolean enableConvertCharacterToString; + boolean usePrettyFormat; + public Builder() { this.allowOpackValueToKeyValue = false; - this.convertCharacterToString = false; - this.prettyFormat = false; + this.enableConvertCharacterToString = false; + this.usePrettyFormat = false; this.encodeStringBufferSize = 1024; this.encodeStackInitialSize = 128; this.decodeStackInitialSize = 128; } - public Builder setAllowOpackValueToKeyValue(boolean allowOpackValueToKeyValue) { - this.allowOpackValueToKeyValue = allowOpackValueToKeyValue; - return this; - } - - public Builder setPrettyFormat(boolean prettyFormat) { - this.prettyFormat = prettyFormat; - return this; - } - public Builder setEncodeStringBufferSize(int encodeStringBufferSize) { this.encodeStringBufferSize = encodeStringBufferSize; return this; @@ -79,6 +69,21 @@ public Builder setDecodeStackInitialSize(int decodeStackInitialSize) { return this; } + public Builder setAllowOpackValueToKeyValue(boolean allowOpackValueToKeyValue) { + this.allowOpackValueToKeyValue = allowOpackValueToKeyValue; + return this; + } + + public Builder setEnableConvertCharacterToString(boolean enableConvertCharacterToString) { + this.enableConvertCharacterToString = enableConvertCharacterToString; + return this; + } + + public Builder setUsePrettyFormat(boolean usePrettyFormat) { + this.usePrettyFormat = usePrettyFormat; + return this; + } + /** * Create the {@link JsonCodec JsonCodec}. * @@ -126,10 +131,6 @@ public JsonCodec create() { CONST_REPLACEMENT_CHARACTERS['\f'] = new char[]{'\\', 'f'}; } - final boolean allowOpackValueToKeyValue; - final boolean convertCharacterToString; - final boolean prettyFormat; - final StringWriter encodeLiteralStringWriter; final StringWriter encodeStringWriter; final FastStack encodeStack; @@ -138,6 +139,10 @@ public JsonCodec create() { final FastStack decodeValueStack; final StringWriter decodeStringWriter; + final boolean allowOpackValueToKeyValue; + final boolean enableConvertCharacterToString; + final boolean usePrettyFormat; + /** * Constructs the JsonCodec with the builder of JsonCodec. * @@ -146,10 +151,6 @@ public JsonCodec create() { JsonCodec(Builder builder) { super(); - this.allowOpackValueToKeyValue = builder.allowOpackValueToKeyValue; - this.convertCharacterToString = builder.convertCharacterToString; - this.prettyFormat = builder.prettyFormat; - this.encodeLiteralStringWriter = new StringWriter(builder.encodeStringBufferSize); this.encodeStringWriter = new StringWriter(builder.encodeStringBufferSize); this.encodeStack = new FastStack<>(builder.encodeStackInitialSize); @@ -157,6 +158,10 @@ public JsonCodec create() { this.decodeBaseStack = new FastStack<>(builder.decodeStackInitialSize); this.decodeValueStack = new FastStack<>(builder.decodeStackInitialSize); this.decodeStringWriter = new StringWriter(); + + this.allowOpackValueToKeyValue = builder.allowOpackValueToKeyValue; + this.enableConvertCharacterToString = builder.enableConvertCharacterToString; + this.usePrettyFormat = builder.usePrettyFormat; } /** @@ -245,7 +250,7 @@ boolean encodeLiteral(Writer writer, Object object) throws IOException { } if (numberType == Character.class) { - if (convertCharacterToString) { + if (enableConvertCharacterToString) { writer.write(CONST_STRING_OPEN_CHARACTER); writer.write(object.toString().toCharArray()); writer.write(CONST_STRING_CLOSE_CHARACTER); @@ -274,7 +279,7 @@ protected void doEncode(Writer writer, OpackValue opackValue) throws IOException FastStack prettyIndentStack = null; - if (this.prettyFormat) { + if (this.usePrettyFormat) { prettyIndentStack = new FastStack<>(); prettyIndentStack.push(0); } @@ -291,13 +296,13 @@ protected void doEncode(Writer writer, OpackValue opackValue) throws IOException } else if (objectType == OpackObject.class) { OpackObject opackObject = (OpackObject) object; int currentIndent = -1; - if (this.prettyFormat) { + if (this.usePrettyFormat) { currentIndent = prettyIndentStack.pop(); } writer.write(CONST_OBJECT_OPEN_CHARACTER); this.encodeStack.push(CONST_OBJECT_CLOSE_CHARACTER); - if (this.prettyFormat && currentIndent != -1) { + if (this.usePrettyFormat && currentIndent != -1) { writer.write(CONST_PRETTY_LINE_CHARACTER); for (int i = 0; i < currentIndent; i++) { this.encodeStack.push(CONST_PRETTY_INDENT_CHARACTER); @@ -310,7 +315,7 @@ protected void doEncode(Writer writer, OpackValue opackValue) throws IOException Object value = opackObject.get(key); if (count != 0) { - if (this.prettyFormat) { + if (this.usePrettyFormat) { if (currentIndent != -1) { this.encodeStack.push(CONST_PRETTY_LINE_CHARACTER); } else { @@ -324,7 +329,7 @@ protected void doEncode(Writer writer, OpackValue opackValue) throws IOException throw new IllegalArgumentException("Object type keys are not allowed in json format."); } - if (this.prettyFormat) { + if (this.usePrettyFormat) { if (value instanceof OpackObject) { prettyIndentStack.push(currentIndent == -1 ? -1 : currentIndent + 1); } @@ -333,12 +338,12 @@ protected void doEncode(Writer writer, OpackValue opackValue) throws IOException } } this.encodeStack.push(value); - if (this.prettyFormat) { + if (this.usePrettyFormat) { this.encodeStack.push(CONST_PRETTY_SPACE_CHARACTER); } this.encodeStack.push(CONST_OBJECT_MAP_CHARACTER); this.encodeStack.push(key); - if (this.prettyFormat && currentIndent != -1) { + if (this.usePrettyFormat && currentIndent != -1) { for (int i = 0; i < currentIndent + 1; i++) { this.encodeStack.push(CONST_PRETTY_INDENT_CHARACTER); } @@ -359,7 +364,7 @@ protected void doEncode(Writer writer, OpackValue opackValue) throws IOException Object value = opackArray.get(index); if (!this.encodeLiteral(this.encodeLiteralStringWriter, value)) { - if (this.prettyFormat) { + if (this.usePrettyFormat) { if (value instanceof OpackObject) { prettyIndentStack.push(-1); } @@ -369,7 +374,7 @@ protected void doEncode(Writer writer, OpackValue opackValue) throws IOException this.encodeStack.swap(this.encodeStack.getSize() - 1, this.encodeStack.getSize() - 2); if (index != size - 1) { this.encodeStack.push(CONST_SEPARATOR_CHARACTER); - if (this.prettyFormat) { + if (this.usePrettyFormat) { this.encodeStack.push(CONST_PRETTY_SPACE_CHARACTER); } } @@ -378,7 +383,7 @@ protected void doEncode(Writer writer, OpackValue opackValue) throws IOException } else { if (index != size - 1) { this.encodeLiteralStringWriter.write(CONST_SEPARATOR_CHARACTER); - if (this.prettyFormat) { + if (this.usePrettyFormat) { this.encodeLiteralStringWriter.write(CONST_PRETTY_SPACE_CHARACTER); } } @@ -448,7 +453,7 @@ protected OpackValue doDecode(String data) throws IOException { case '}': case ']': { if (this.decodeValueStack.getSize() - 1 != this.decodeBaseStack.peek()) { - throw new IOException("Expected literal value, but got close syntax character at " + pointer + "(" + currentChar + ")"); + throw new IOException("Expected literal value, but got close syntax character at " + pointer + "(" + currentChar + ")."); } this.decodeBaseStack.pop(); @@ -459,7 +464,7 @@ protected OpackValue doDecode(String data) throws IOException { case ',': case ':': { if (literalMode) { - throw new IOException("Expected literal value, but got syntax character at " + pointer + "(" + currentChar + ")"); + throw new IOException("Expected literal value, but got syntax character at " + pointer + "(" + currentChar + ")."); } int baseIndex = this.decodeBaseStack.peek(); @@ -471,7 +476,7 @@ protected OpackValue doDecode(String data) throws IOException { case ',': { if (objectType == OpackObject.class) { if (valueSize != 0) { - throw new IOException("The map type cannot contain items that do not exist. at " + pointer + "(" + currentChar + ")"); + throw new IOException("The map type cannot contain items that do not exist. at " + pointer + "(" + currentChar + ")."); } } @@ -480,11 +485,11 @@ protected OpackValue doDecode(String data) throws IOException { case ':': { if (objectType == OpackObject.class) { if (valueSize != 1) { - throw new IOException("The map item must have a key. at " + pointer + "(" + currentChar + ")"); + throw new IOException("The map item must have a key. at " + pointer + "(" + currentChar + ")."); } } if (objectType == OpackArray.class) { - throw new IOException("The array type cannot contain colons. at " + pointer + "(" + currentChar + ")"); + throw new IOException("The array type cannot contain colons. at " + pointer + "(" + currentChar + ")."); } break; @@ -539,7 +544,7 @@ protected OpackValue doDecode(String data) throws IOException { } else if (unicode >= 'A' && unicode <= 'F') { result += (unicode - 'A' + 10); } else { - throw new IOException("Parsed unknown unicode pattern at " + pointer + "(" + unicode + ")"); + throw new IOException("Parsed unknown unicode pattern at " + pointer + "(" + unicode + ")."); } } this.decodeStringWriter.write(result); @@ -603,10 +608,10 @@ protected OpackValue doDecode(String data) throws IOException { pointer = pointer + 3; stackMerge = true; } else { - throw new IOException("This value is not an opack value. Unknown value at " + pointer + "(" + currentChar + ")"); + throw new IOException("This value is not an opack value. Unknown value at " + pointer + "(" + currentChar + ")."); } } else { - throw new IOException("Parsed unknown character at " + pointer + "(" + currentChar + ")"); + throw new IOException("Parsed unknown character at " + pointer + "(" + currentChar + ")."); } } } @@ -637,7 +642,7 @@ protected OpackValue doDecode(String data) throws IOException { opackArray.add(value); } } else { - throw new IOException("Caught corrupted stack, got " + objectType.getSimpleName()); + throw new IOException("Caught corrupted stack, got " + objectType.getSimpleName() + "."); } } } diff --git a/src/main/java/com/realtimetech/opack/util/OpackArrayConverter.java b/src/main/java/com/realtimetech/opack/util/OpackArrayConverter.java index 4d5e876..5e53ac9 100644 --- a/src/main/java/com/realtimetech/opack/util/OpackArrayConverter.java +++ b/src/main/java/com/realtimetech/opack/util/OpackArrayConverter.java @@ -39,7 +39,7 @@ public class OpackArrayConverter { try { method = Class.forName("com.realtimetech.opack.value.AbstractOpackValue").getDeclaredMethod("get"); } catch (NoSuchMethodException | ClassNotFoundException e) { - throw new ExceptionInInitializerError("No getter method found in OpackArray"); + throw new ExceptionInInitializerError("No getter method found in OpackArray."); } OPACK_ARRAY_GETTER_METHOD = method; OPACK_ARRAY_GETTER_METHOD.setAccessible(true); diff --git a/src/main/java/com/realtimetech/opack/value/OpackArray.java b/src/main/java/com/realtimetech/opack/value/OpackArray.java index 671fdef..2eddf8c 100644 --- a/src/main/java/com/realtimetech/opack/value/OpackArray.java +++ b/src/main/java/com/realtimetech/opack/value/OpackArray.java @@ -64,15 +64,15 @@ public static OpackArray createWithArrayObject(@NotNull Object arrayObject) { */ OpackArray(@NotNull Object arrayObject) { if (!arrayObject.getClass().isArray()) { - throw new IllegalArgumentException(arrayObject + " is not array object"); + throw new IllegalArgumentException(arrayObject + " is not array object."); } if (ReflectionUtil.getArrayDimension(arrayObject.getClass()) != 1) { - throw new IllegalArgumentException(arrayObject + " must have 1 dimension"); + throw new IllegalArgumentException(arrayObject + " must have 1 dimension."); } if (!OpackArray.isAllowArray(arrayObject.getClass())) { - throw new IllegalArgumentException(arrayObject + " array element is not allowed type, allow only primitive type or String or OpackValues or null"); + throw new IllegalArgumentException(arrayObject + " array element is not allowed type, allow only primitive type or String or OpackValues or null."); } this.set((List) new NativeList(arrayObject)); diff --git a/src/main/java/com/realtimetech/opack/value/OpackValue.java b/src/main/java/com/realtimetech/opack/value/OpackValue.java index 081a48c..d86ed89 100644 --- a/src/main/java/com/realtimetech/opack/value/OpackValue.java +++ b/src/main/java/com/realtimetech/opack/value/OpackValue.java @@ -33,7 +33,7 @@ public interface OpackValue { */ public static void assertAllowType(Class type) { if (!OpackValue.isAllowType(type)) { - throw new IllegalArgumentException(type.getName() + " is not allowed type, allow only primitive type or String or OpackValues or null"); + throw new IllegalArgumentException(type.getName() + " is not allowed type, allow only primitive type or String or OpackValues or null."); } } diff --git a/src/test/java/com/realtimetech/opack/test/OpackAssert.java b/src/test/java/com/realtimetech/opack/test/OpackAssert.java index 16f27b9..e862c40 100644 --- a/src/test/java/com/realtimetech/opack/test/OpackAssert.java +++ b/src/test/java/com/realtimetech/opack/test/OpackAssert.java @@ -59,7 +59,7 @@ static void assertObject(Object original, Object target) throws AssertException OpackAssert.assertSingleValue(originalObject, targetObject); } catch (IllegalAccessException e) { - throw new IllegalArgumentException("Assert failure, throw illegal access exception when get field value"); + throw new IllegalArgumentException("Assert failure, throw illegal access exception when get field value."); } catch (AssertException exception) { throw new FieldAssertException(original.getClass(), field.getName(), exception); } @@ -72,11 +72,11 @@ static void throwException(Object originalObject, Object targetObject) throws As } static void throwException(String property, Object originalValue, Object targetValue) throws AssertException { - throw new AssertException("Assert failure, expected " + property + " is \"" + originalValue + "\" but got \"" + targetValue + "\""); + throw new AssertException("Assert failure, expected " + property + " is \"" + originalValue + "\" but got \"" + targetValue + "\"."); } static void throwExceptionNotContains(Object originalValue) throws AssertException { - throw new AssertException("Assert failure, originally contains " + originalValue + " but not contains"); + throw new AssertException("Assert failure, originally contains " + originalValue + " but not contains."); } static void assertSingleValue(Object originalObject, Object targetObject) throws AssertException { diff --git a/src/test/java/com/realtimetech/opack/test/opacker/EnumTest.java b/src/test/java/com/realtimetech/opack/test/opacker/EnumTest.java index 3303c79..a114a37 100644 --- a/src/test/java/com/realtimetech/opack/test/opacker/EnumTest.java +++ b/src/test/java/com/realtimetech/opack/test/opacker/EnumTest.java @@ -61,7 +61,7 @@ public void test() throws SerializeException, DeserializeException, OpackAssert. OpackAssert.assertEquals(originalObject, deserialized); } { - Opacker opacker = new Opacker.Builder().setConvertEnumToOrdinal(true).create(); + Opacker opacker = new Opacker.Builder().setEnableConvertEnumToOrdinal(true).create(); EnumTest.EnumClass originalObject = new EnumTest.EnumClass(); OpackValue serialized = opacker.serialize(originalObject); diff --git a/src/test/java/com/realtimetech/opack/test/opacker/IgnoreFieldTest.java b/src/test/java/com/realtimetech/opack/test/opacker/IgnoreFieldTest.java index 8a5f41d..9ea157d 100644 --- a/src/test/java/com/realtimetech/opack/test/opacker/IgnoreFieldTest.java +++ b/src/test/java/com/realtimetech/opack/test/opacker/IgnoreFieldTest.java @@ -53,7 +53,7 @@ public void test() throws SerializeException, DeserializeException, OpackAssert. OpackAssert.assertEquals(originalObject, deserialized); if (deserialized.ignoredField != null) { - throw new OpackAssert.AssertException("The IgnoreFieldTestClass.ignoredField field was not ignored"); + throw new OpackAssert.AssertException("The IgnoreFieldTestClass.ignoredField field was not ignored."); } } diff --git a/src/test/java/com/realtimetech/opack/test/opacker/RecursiveLoopTest.java b/src/test/java/com/realtimetech/opack/test/opacker/RecursiveLoopTest.java new file mode 100644 index 0000000..1351c23 --- /dev/null +++ b/src/test/java/com/realtimetech/opack/test/opacker/RecursiveLoopTest.java @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2022 REALTIMETECH All Rights Reserved + * + * Licensed either under the Apache License, Version 2.0, or (at your option) + * under the terms of the GNU General Public License as published by + * the Free Software Foundation (subject to the "Classpath" exception), + * either version 2, or any later version (collectively, the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.gnu.org/licenses/ + * http://www.gnu.org/software/classpath/license.html + * + * or as provided in the LICENSE file that accompanied this code. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.realtimetech.opack.test.opacker; + +import com.realtimetech.opack.Opacker; +import com.realtimetech.opack.exception.DeserializeException; +import com.realtimetech.opack.exception.SerializeException; +import com.realtimetech.opack.test.OpackAssert; +import com.realtimetech.opack.value.OpackValue; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class RecursiveLoopTest { + public static class RecursiveClass { + private RecursiveClass recursiveClass; + + public RecursiveClass() { + } + + public void setRecursiveClass(RecursiveClass recursiveClass) { + this.recursiveClass = recursiveClass; + } + } + + @Test + public void test() throws SerializeException, DeserializeException, OpackAssert.AssertException { + Opacker opacker = new Opacker.Builder() + .setEnableConvertRecursiveDependencyToNull(false) + .create(); + RecursiveClass originalObjectA = new RecursiveClass(); + RecursiveClass originalObjectB = new RecursiveClass(); + + originalObjectA.setRecursiveClass(originalObjectB); + originalObjectB.setRecursiveClass(originalObjectA); + + try { + OpackValue serialized = opacker.serialize(originalObjectA); + + Assertions.fail("Not detected recursive dependency."); + } catch (SerializeException exception) { + // Ok! + } + } +}