jdereg / json-io Goto Github PK
View Code? Open in Web Editor NEWConvert Java to JSON. Convert JSON to Java. Pretty print JSON. Java JSON serializer. Deep copy Java object graphs.
License: Apache License 2.0
Convert Java to JSON. Convert JSON to Java. Pretty print JSON. Java JSON serializer. Deep copy Java object graphs.
License: Apache License 2.0
When objects contain fields with NaN, Infinity or -Infinity, an invalid JSON string is produced.
ex:
class O {
double num = Double.NaN;
}
JSONWriter.objectToJson( new O() );
// {"num": NaN}
in contrast v8's implementation turns these into null
JSON.stringify({'num', NaN})
// {"num": null}
Hi,
I wonder if there is a switch to turn off the @ref feature. I'd rather have it repeat the object for each occurrence.
Thanks!
My application is extendable with plugins that can be loaded and unloaded. Data from these plugins can be stored on the objects I use json-io to serialize to disk. So its not uncommon that when deserializing the json-io file some field/object in this key map reference an unloaded plugin/class that doesn't exist. In this case, does json-io return null or does it throw an exception? My wish would be that it just ignored the field and continued with the rest.
When I previously used XMLEncoder/XMLDecoder to do the job I used setExceptionListener() and in the custom ExceptionListener checked if the exception was of instance ClassNotFoundException or NullPointerException and in those cases just suppressed them, else I logged the error and continued.
Is this possible in json-io or is it something that could be added?
if we have an object that has fields not to be serialized in certain cases, which means we cannot use transient for this, there is not way to specify this.
I thought I could be using the FIELD_SPECIFIERS to specify a white list of field thus removing the fields from this list but there is an issue with subclasses that does not allow this for subclasses ( see #78 ).
SO what would be great is to have a black list of field not be serialized.
I'll try to create a PR for this.
Hi,
I'm trying to serialize/deserialize DataHandler (http://docs.oracle.com/javase/7/docs/api/javax/activation/DataHandler.html) object to json and vice versa, but it occurs an error during the process:
{"@type":"javax.activation.DataHandler","dataSource":{"@type":"javax.activation.URLDataSource","url":{"protocol":"http","host":"www.google.com","port":-1,"file":"","authority":"www.google.com","ref":null,"hashCode":-1},"url_conn":null},"objDataSource":null,"object":null,"objectMimeType":null,"currentCommandMap":null,"transferFlavors":[],"dataContentHandler":null,"factoryDCH":null,"oldFactory":null,"shortType":null}
Exception in thread "main" java.io.IOException: IllegalAccessException setting field 'url' on target: javax.activation.URLDataSource@e5590e with value: {protocol=http, host=www.google.com, port=-1, file=, authority=www.google.com, ref=null, hashCode=-1}
Last read: "transferFlavors":[],"dataContentHandler":null,"factoryDCH":null,"oldFactory":null,"shortType":null}
line: 1, col: 419
at com.cedarsoftware.util.io.JsonReader.error(JsonReader.java:3199)
at com.cedarsoftware.util.io.JsonReader.assignField(JsonReader.java:1863)
at com.cedarsoftware.util.io.JsonReader.traverseFields(JsonReader.java:1731)
at com.cedarsoftware.util.io.JsonReader.convertMapsToObjects(JsonReader.java:1263)
at com.cedarsoftware.util.io.JsonReader.convertParsedMapsToJava(JsonReader.java:1202)
at com.cedarsoftware.util.io.JsonReader.readObject(JsonReader.java:1166)
at com.cedarsoftware.util.io.JsonReader.jsonToJava(JsonReader.java:1084)
at prova.gson.App.main(App.java:24)
Caused by: java.io.IOException: Could not instantiate java.net.URL using any constructor
Last read: "transferFlavors":[],"dataContentHandler":null,"factoryDCH":null,"oldFactory":null,"shortType":null}
line: 1, col: 419
at com.cedarsoftware.util.io.JsonReader.error(JsonReader.java:3194)
at com.cedarsoftware.util.io.JsonReader.tryOtherConstructors(JsonReader.java:2679)
at com.cedarsoftware.util.io.JsonReader.newInstanceEx(JsonReader.java:2639)
at com.cedarsoftware.util.io.JsonReader.newInstance(JsonReader.java:2615)
at com.cedarsoftware.util.io.JsonReader.createJavaObjectInstance(JsonReader.java:2112)
at com.cedarsoftware.util.io.JsonReader.assignField(JsonReader.java:1838)
... 6 more
This is my code snippet:
package mypackage;
import java.io.IOException;
import java.net.URL;
import javax.activation.DataHandler;
import javax.activation.DataSource;
import com.cedarsoftware.util.io.JsonReader;
import com.cedarsoftware.util.io.JsonWriter;
public class App
{
public static void main( String[] args ) throws IOException
{
DataHandler obj = new DataHandler(new URL("http://www.google.com"));
String json = JsonWriter.objectToJson(obj);
System.out.println(json);
Object obj2 = JsonReader.jsonToJava(json);
}
}
at the moment the library does not work with jdk 6
Adding these lines to the end of TestSet.testSet() shows the problem.
```
testSet._enumSet.remove(ManySets.EnumValues.E1);
testSet._enumSet.remove(ManySets.EnumValues.E2);
testSet._enumSet.remove(ManySets.EnumValues.E3);
json = TestUtil.getJsonString(testSet)
testSet = (ManySets) TestUtil.readJsonObject(json)
testSet._enumSet.add(ManySets.EnumValues.E1);
The problem is the elementType is null when the EnumSet is deserialized, and then it cannot be used to add values. The elementType needs to be retained during the serialization/deserialization process and it's not.
it is sometimes useful, when the object graph is very big, to define maximum depth for the traversal.
is it possible to do today?
Without this, any user classes are not found when deserializing in an OSGi environment.
PR to come.
In Javascript it is easy and straight forward to use a json string as associative array with just a single line of code, if it is in the notation
{
key0=val0;
key1=val1;
}
Thus, it is perfect to deal with json generated by json-io out of java bean or pojo like Objects. I am wondering about why the generated json is different if the input is a java Map. Sadly, the generated json looks like this:
{
"@keys":[
"key0",
"key1"
],
"@items":[
"val0",
"val1"
]
}
This is hard to read by humans as with more entries, it's not clear which value is associated with a key. It's hard to use programatically, since it's 'somehow special'. Last but not least, it's different to other json serializing libraries, which makes it hart for both server and client code to switch if you want to enjoy the advantages of json-io.
Is there a need for this additional syntax? I would ask for a feature request, or a hint how I can achieve the default json object associative syntax also for maps (maybe with a custom writer/reader).
I am attempting to serialize a class containing a Map that has Longs as keys.
This is failing with
java.lang.ClassCastException: java.lang.Long cannot be cast to java.lang.String
at com.cedarsoftware.util.io.JsonWriter.writeMapBody(JsonWriter.java:1982) ~[json-io-2.9.1.jar:?]
at com.cedarsoftware.util.io.JsonWriter.writeMapWithStringKeys(JsonWriter.java:1972) ~[json-io-2.9.1.jar:?]
at com.cedarsoftware.util.io.JsonWriter.writeImpl(JsonWriter.java:1012) ~[json-io-2.9.1.jar:?]
at com.cedarsoftware.util.io.JsonWriter.writeField(JsonWriter.java:2154) ~[json-io-2.9.1.jar:?]
The method ensureJsonPrimitiveKeys returns true. It checks that the key is (o instanceof String || o instanceof Double || o instanceof Long || o instanceof Boolean)
but then method writeMapBody assumes the key is a String on line 1982
output.write((String) att2value.getKey());
Thanks for your lib, I use it in my everyday work extensively but I still cant figure out how to deserialize list of objects. Now I have to make a top level wrapper where I can put my list of objects and then I deserialize this wrapper and get the data from it's field. But it seems a bit excessively. Is there better way to do this?
Something like
List<MyData> objectList;
String jsonString = JsonWriter.objectToJson(list);
and then
List<MyData> deserObjectList = JsonReader.jsonToJava(jsonString, MyData.class)
Even though I added a TYPE arg of true to the writer it did not output @type for all data types. The values in the hashtable for object serialized to disk, int, date and float types has the @type but strings and long does not.
The writer code:
Map<String,Object> params = new HashMap<String,Object>();
params.put(JsonWriter.PRETTY_PRINT, true);
params.put(JsonWriter.TYPE, true);
JsonWriter writer = new JsonWriter(out, params);
writer.write(this);
example output:
{
"@type":"int",
"value":1
},
"Some string value",
{
"@type":"date",
"value":4102441199000
},
2234,
One of the recent updates changed how JS arrays are parsed. Previously it used to be JsonObject
instances, but now it's just Object[]
which so I've got to fix a lot of ClassCastException
issues.
Shouldn't JsonObject.getArray
and JsonObject.isArray
be completely @Depricated
at this point? Or is there still a use case for those?
I ran some benchmarks using JMH against a bunch of Java JSON libraries (jackson, gson, genson, org.json, etc.) and added json-io to my panel of tests and was very surprised (not to say chocked) about the performance of json-io.
The results are here: https://github.com/fabienrenaud/java-json-benchmark
json-io performs comparably to org.json...
I read the readme documentation of json-io and couldn't find any hints about how to boost performance nor couldn't find anything I could use to get better result (and I want to :) ).
Did I miss something?
As I was using json-io, I noticed that although capable of dealing with POJOS, it doesn't surface any factories. Maybe those are hidden internally...
Did you try to profile (i guess with YourKit?) the project to see if there isn't some obvious bottlenecks that can easily be fixed?
Hello,
Here is the documentation for FIELD_SPECIFIER map option for serializing objects
// Set value to a Map<Class, List<String>> which will be used to control which fields on a class are output
So what I understand from this is that it will only specify the field for given class to be serialized but implicitly means that subclasses fields shall be serialized.
But this is not the case.
here is the test case that show the opposite.
@Test
void testExternalFieldSpecifierInheritance()
{
Map<Class, List<String>> fieldSpecifiers = [(PainfulToSerialize.class):['name']]
MorePainfulToSerialize painful = new MorePainfulToSerialize()
painful.name = "Android rocks"
painful.age = 50;
def args = [(JsonWriter.FIELD_SPECIFIERS):fieldSpecifiers]
String json = JsonWriter.objectToJson(painful, args)
Map check = (Map) JsonReader.jsonToJava(json, [(JsonReader.USE_MAPS):true] as Map)
assertTrue(check.size() == 1)
assertTrue(check.containsKey("name"))
here I would expect the MorePainfulToSerialize.age to be serialized because we only specified the name field for the parent class PainfulToSerialize.
So now if you specify a FIELD_SPECIFIERS for a given class, all fields that are added in subclasses will never be serialized which seems strange and make this feature not very useful I think.
in many cases java objects have some set of fields with null values.
(it can be even huge)
the option to do not write such fields will be very useful.
It seems to me that this is because of the special treatment of Maps inside JsonWriter:
....
else if (Map.class.isAssignableFrom(clazz))
{ // Speed up - logically walk maps, as opposed to following their internal structure.
Map map = (Map) obj;
for (final Object item : map.entrySet())
{
final Map.Entry entry = (Map.Entry) item;
if (entry.getValue() != null)
{
stack.addFirst(entry.getValue());
}
if (entry.getKey() != null)
{
stack.addFirst(entry.getKey());
}
}
}
I have a subclass of LinkedHashMap that implements a LRUCache, but suddenly it doesn't work with json-io. There, a member with the maximum amount of entries is necessary, which becomes zero after deserialization.
I have a strange error while deserializing one of my data structures. The structure is too complex to post it here, but I managed it to create a small snippet to reproduce the problem:
import com.cedarsoftware.util.io.JsonReader;
import com.cedarsoftware.util.io.JsonWriter;
public class FeldWaldWiese
{
static public class Test<K, V>
{
// WORKING:
// protected Test2 m_internalHashMap = new Test2();
// NOT WORKING:
protected Test2<K, V> m_internalObject = new Test2<>();
}
static public class Test2<K, V>
{
//strange: if I leave just one of the members, it is working.
//Maybe the member count is relevant. It seems to be independent from the members type
int i;
int y;
String check;
}
public static void main(String[] args) throws Exception
{
Test item = new Test();
JsonReader.jsonToJava(JsonWriter.objectToJson(item));
}
}
the snippet generates following exception:
Exception in thread "main" java.io.IOException: ArrayIndexOutOfBoundsException setting field 'm_internalObject' on target: org.dynaq.FeldWaldWiese$Test@4e5a5622 with value: {i=0, y=0, check=null}
Last read: {"@type":"org.dynaq.FeldWaldWiese$Test","m_internalObject":{"i":0,"y":0,"check":null}}
line: 1, col: 87
at com.cedarsoftware.util.io.JsonReader.error(JsonReader.java:3238)
at com.cedarsoftware.util.io.JsonReader.assignField(JsonReader.java:1894)
at com.cedarsoftware.util.io.JsonReader.traverseFields(JsonReader.java:1762)
at com.cedarsoftware.util.io.JsonReader.convertMapsToObjects(JsonReader.java:1294)
at com.cedarsoftware.util.io.JsonReader.convertParsedMapsToJava(JsonReader.java:1233)
at com.cedarsoftware.util.io.JsonReader.readObject(JsonReader.java:1193)
at com.cedarsoftware.util.io.JsonReader.jsonToJava(JsonReader.java:1085)
at org.dynaq.FeldWaldWiese.main(FeldWaldWiese.java:32)
Caused by: java.lang.ArrayIndexOutOfBoundsException: 2
at com.cedarsoftware.util.io.JsonReader.markUntypedObjects(JsonReader.java:1991)
at com.cedarsoftware.util.io.JsonReader.assignField(JsonReader.java:1792)
... 6 more
If I leave the type parameters from the member in the container class 'Test', no exception will be thrown. If I leave one of the parameters inside the class 'Test2', also no exception is thrown. It seems to me that the problem starts if more than 2 member variables are in the second class.
The snippet was executed with Oracle Java JDK 1.7.0_60.
Use case:
P.S. For interfaces, I'd also appreciate the ability to stick to a default implementation explicitly (i.e. override the concrete type upon deserialization - of course, within types assignable to the declared field type).
Sometimes it's nice to be able to replace a value both when reading and writing for a specific field, to encode an encrypted password for example.
I will provide a pull request to implement this.
Currently the custom reader mechanism does not allow you to automatically read the current object, it has to be done entirely manually.
The use case for this and #75 is to be able to add a single field to the serialized output of certain objects (to track a version number), but otherwise read and write the object automatically and normally.
A pull request will be provided.
I was trying to use json-io as part of serializing/deserializing apache storm structures. Storm is written partly in java and partly in clojure. I assumed clojure being JVM compliant json-io should not have any issues serializing/deserializing clojure structures but that is not the case. Following example shows how the deserialization fails for the PersistanceArrayMap structure of clojure which is implemented in java. It seems for the map implementation the code assumes the put method is always supported which is incorrect for any immutable implementation of map. I also tried to serialize Guava's immutable maps and got the same result.
Guava Code Sample:
ImmutableMap<Object, Object> map = ImmutableMap.builder().put("a", "b").build();
String s = JsonWriter.objectToJson(map);
System.out.println(map);
Object o = JsonReader.jsonToJava(s);
System.out.println(o);
Exception:
{a=b}
Exception in thread "main" java.lang.UnsupportedOperationException
at com.google.common.collect.ImmutableMap.put(ImmutableMap.java:326)
at com.cedarsoftware.util.io.JsonReader.rehashMaps(JsonReader.java:3418)
at com.cedarsoftware.util.io.JsonReader.convertParsedMapsToJava(JsonReader.java:1320)
at com.cedarsoftware.util.io.JsonReader.readObject(JsonReader.java:1278)
at com.cedarsoftware.util.io.JsonReader.jsonToJava(JsonReader.java:1169)
Clojure Code Sample:
String s = JsonWriter.objectToJson(clojure.lang.RT.assoc(null, "a", "b"));
System.out.println(s);
Object o = JsonReader.jsonToJava(s);
System.out.println(o);
Exception:
Exception in thread "main" java.lang.UnsupportedOperationException
{"@type":"clojure.lang.PersistentArrayMap","a":"b"}
at clojure.lang.APersistentMap.put(APersistentMap.java:285)
at com.cedarsoftware.util.io.JsonReader.rehashMaps(JsonReader.java:3418)
at com.cedarsoftware.util.io.JsonReader.convertParsedMapsToJava(JsonReader.java:1320)
at com.cedarsoftware.util.io.JsonReader.readObject(JsonReader.java:1278)
at com.cedarsoftware.util.io.JsonReader.jsonToJava(JsonReader.java:1169)
generic Exception is caught in JsonReader but the error message states IllegalAccessException.
Proposed: replace with e.getClass().getSimpleName()
Hello.
I can't figure out how to use PUBLIC_FIELDS as described here: https://github.com/jdereg/json-io/blob/master/src/main/java/com/cedarsoftware/util/io/JsonWriter.java#L158 .
In fact, I can't find the string "PUBLIC_FIELDS" in the source other than inside javadoc comments. ...I'm eager to know what I'm missing here. :)
Cheers, thanks,
--Dave
Assuming the lib doesn't use any newer Java features, could the source be recompiled so it's compatible with older versions of Java?
Being a JDK 1.6 user I currently get:
Unsupported major.minor version 51.0
This SO question explains a bit more if you're unsure.
I know I can do it myself, but it's always nice not having to build from source.
I'm coding a JavaFX application and I want to serialize/deserialize a list of objects that are observable cause they are used in a TableView
. I tested that the serialization/deserialization with json-io of a List
works well, but when I try to do the same thing with an ObservableList
I get JsonIoException
when calling readObject()
from the JsonReader
instance
This is the failure trace from JUnit
com.cedarsoftware.util.io.JsonIoException: null
Last read: afx.beans.property.SimpleObjectProperty","bean":null,"name":"","value":{"@type":"java.time.LocalDate","year":2015,"month":6,"day":21},"observable":null,"listener":null,"valid":true,"helper":null}}]}}v
line: 1, col: 3721
at com.cedarsoftware.util.io.JsonReader.convertParsedMapsToJava(JsonReader.java:598)
at com.cedarsoftware.util.io.JsonReader.readObject(JsonReader.java:540)
at tests.unit.LibraryJsonSerializeTest.testObservableListToLibrary(LibraryJsonSerializeTest.java:69)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
Caused by: java.lang.NullPointerException
at com.sun.javafx.collections.ObservableListWrapper.size(ObservableListWrapper.java:94)
at java.util.AbstractList.add(AbstractList.java:108)
at com.cedarsoftware.util.io.ObjectResolver.traverseCollection(ObjectResolver.java:325)
at com.cedarsoftware.util.io.Resolver.convertMapsToObjects(Resolver.java:122)
at com.cedarsoftware.util.io.JsonReader.convertParsedMapsToJava(JsonReader.java:584)
... 25 more
Any ideas about the reason?
We give the possibility to specify http get parameters also as json strings, to allow class objects as parameter types for the web interfaces also.
The problem is, by using json-io, specifying @type in the json string is mandatory for deserialization, right? Thus, the users have to specify it, which is not so nice (for the return values its fine of course, but for parameters?)
I love the way json-io deals with types, for me, it is the best solution to support polymorphism I have seen in such a library. Nevertheless, in this case, the underlying type of the parameter normally not changes - it should be transparent for the (e.g. javascript) user of the interface who creates the json, and clear for the server.
Is it possible to add another method to JsonReader.jsonToJava(String json, Class toplevelFallbackType) - where toplevelFallbackType could be also String, Type, etc. of course.
This parameter would then be used as fallback if the @type was not specified in the toplevel json object.
I know this would not work with polymorphism, but it would help us a lot and would be maybe a nice enhanchement of json-ios functionality:)
Thanks and best regards
Christian
Currently, T (or K / V) is consider a type directly, but not as a potentially nested type, for example List<List>. In this example, T at the outer level is List. Need to handle support for unlimited nesting within template parameters, in the code that uses the template parameters to infer Collection or Map object types, when type is not set within the Collection or Map contents.
In JsonWriter @ private void writeArray(Object array, boolean showType)
line 888:
boolean typeWritten = showType && !(Object[].class == arrayType);
For a reason I cannot explain due to my little knowledge of Java, the type verification for array appears invalid in Netbeans 7.4, Java 1.7, Win7
the particular error message is "lambda expression not expected here illegal start of expression ..."
I tried using
boolean typeWritten = showType && !(array instanceof Object[]);
This seems to remove that error message, but since my knowledge of Java is limited, I was hoping you could check if this is correct, and if so, perhaps change the particular line of code.
Thanks for reading this,
Have a nice day!
P.S. If this is not applicable, please remove the issue, and if possible let me know.
Object obj = JsonReader.jsonToJava(json, [(JsonReader.USE_MAPS): true)]) extra paren
Employee emp = (Employee) JsonReader.jsonToJava(stream); extra equals
Related to #32 , but a bit different and can't be solved with assignInstantiator.
json-IO fails to deserialize Collections.SingletonMap instance:
@Test
void testSingletonMap()
{
Map root1 = Collections.singletonMap( "testCfgKey", "testCfgValue" )
String json = JsonWriter.objectToJson(root1)
Map root2 = (Map) JsonReader.jsonToJava(json)
}
Caused by: java.lang.UnsupportedOperationException
at java.util.AbstractMap.put(AbstractMap.java:209)
at com.cedarsoftware.util.io.Resolver.rehashMaps(Resolver.java:556)
at com.cedarsoftware.util.io.Resolver.cleanup(Resolver.java:139)
at com.cedarsoftware.util.io.JsonReader.convertParsedMapsToJava(JsonReader.java:596)
Discussion about the same issue in Jackson: FasterXML/jackson-core#218
Is it possible to omit the "@type" property when writing? I didn't find in the documentation whether it is possible but it doesn't state why the property is there. My use case doesn't need it since I don't convert my data back to Java objects.
In version 2.6.1, if I don't want to have the java object but only the map representation of the json (by giving the constructor 'true' for noObjects), convertParsedMapsToJava is still invoked - is this necessary or simply an unnecessary overhead in this case? This is the readObject() code from JsonReader:
public Object readObject() throws IOException
{
Object o = readJsonObject();
if (o == EMPTY_OBJECT)
{
return new JsonObject();
}
Object graph = convertParsedMapsToJava((JsonObject) o);
// Allow a complete 'Map' return (Javascript style)
if (_noObjects)
{
return o;
}
return graph;
}
Maybe it could be more efficient if convertParsedMapsToJava is only invoked if necessary:
public Object readObject() throws IOException
{
Object o = readJsonObject();
if (o == EMPTY_OBJECT)
{
return new JsonObject();
}
// Allow a complete 'Map' return (Javascript style)
if (_noObjects)
{
return o;
}
Object graph = convertParsedMapsToJava((JsonObject) o);
return graph;
}
I downloaded the 2.9.2 library to support Android > 5.0. It works well, but on devices lower 5 the following error is thrown:
02-09 14:20:22.210: E/AndroidRuntime(18869): java.lang.VerifyError: com/cedarsoftware/util/io/JsonReader
02-09 14:20:22.210: E/AndroidRuntime(18869): at com.cedarsoftware.util.io.JsonWriter.traceReferences(JsonWriter.java:791)
02-09 14:20:22.210: E/AndroidRuntime(18869): at com.cedarsoftware.util.io.JsonWriter.write(JsonWriter.java:759)
02-09 14:20:22.210: E/AndroidRuntime(18869): at com.cedarsoftware.util.io.JsonWriter.objectToJson(JsonWriter.java:209)
02-09 14:20:22.210: E/AndroidRuntime(18869): at com.cedarsoftware.util.io.JsonWriter.objectToJson(JsonWriter.java:163)
If a transient object cannot be examined and gives an exception it will blow up the serialization. transient objects should not be accessed for serialization.
I will supply a pull request for this.
Currently the custom writer support does not allow you to simple add a field and then write the current object normally. You can write a child object, but not the current one.
A pull request will be provided.
Concerns version json-io-2.6.0
.
I would like to write 2 objects to a stream without closing it in-between. I get a NullPointerException
when I write the second object.
FileOutputStream fos = new FileOutputStream("test.bin");
ObjectOutputStream oos = new ObjectOutputStream(fos);
JsonWriter jwr = new JsonWriter(oos);
jwr.write("Hello");
jwr.write("World");
On the second JsonWriter.write(Object o)
, I get the NullPointerException
:
Exception in thread "main" java.lang.NullPointerException
at com.cedarsoftware.util.io.JsonWriter.getFieldsUsingSpecifier(JsonWriter.java:799)
at com.cedarsoftware.util.io.JsonWriter.traceFields(JsonWriter.java:757)
at com.cedarsoftware.util.io.JsonWriter.traceReferences(JsonWriter.java:740)
at com.cedarsoftware.util.io.JsonWriter.write(JsonWriter.java:683)
at Test.main(Test.java:19)
Is it possible to write multiple objects with JsonWriter
? Is json-io
designed to write multiple objects to stream, or am I missing something here?
Is it also possible to read multiple objects with JsonReader
?
Having the following code:
public class ADouble<T> {
private T field1;
private T field2;
public ADouble(T field1, T field2) {
this.field1 = field1;
this.field2 = field2;
}
}
public class UseADouble {
private ADouble<String> a;
public UseADouble(ADouble<String> a) {
this.a = a;
}
}
And the following test:
@Test
public void testDouble() throws IOException {
UseADouble o = new UseADouble(new ADouble<String>("1","2"));
String json = JsonWriter.objectToJson(o);
//this will crash on ArrayIndexOutOfBoundsException
Object ha2 = JsonReader.jsonToJava(json);
System.out.println(ha2);
}
The serialization works just fine:
{"@type":"UseADouble","a":{"field1":"1","field2":"2"}}
However trying to deserialize given JSON, I get an ArrayIndexOutOfBoundsException
exception:
java.io.IOException: ArrayIndexOutOfBoundsException setting field 'a' on target: UseADouble@e74e382 with value: {field1=1, field2=2}
Last read: {"@type":"UseADouble","a":{"field1":"1","field2":"2"}}
line: 1, col: 55
at com.cedarsoftware.util.io.JsonReader.error(JsonReader.java:3296)
at com.cedarsoftware.util.io.JsonReader.assignField(JsonReader.java:1947)
at com.cedarsoftware.util.io.JsonReader.traverseFields(JsonReader.java:1815)
at com.cedarsoftware.util.io.JsonReader.convertMapsToObjects(JsonReader.java:1347)
at com.cedarsoftware.util.io.JsonReader.convertParsedMapsToJava(JsonReader.java:1286)
at com.cedarsoftware.util.io.JsonReader.readObject(JsonReader.java:1246)
at com.cedarsoftware.util.io.JsonReader.jsonToJava(JsonReader.java:1137)
at HomeAwayTest.testDouble(HomeAwayTest.java:79)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.junit.runner.JUnitCore.run(JUnitCore.java:160)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:67)
Caused by: java.lang.ArrayIndexOutOfBoundsException: 1
at com.cedarsoftware.util.io.JsonReader.markUntypedObjects(JsonReader.java:2044)
at com.cedarsoftware.util.io.JsonReader.assignField(JsonReader.java:1845)
... 28 more
It has a problem because it can't be initialized with the normal constructor stuff.
Pull request to come in a little bit.
com.cedarsoftware.util.io.JsonIoException: class org.talend.components.api.properties.Property$Flags != null
Last read: title":"Restore Test"}]},"validationResult":null,"propertyValues":{"@type":"java.util.HashMap","@keys":[{"@ref":24},{"@ref":11}],"@Items":["testPassword","testUser"]}},"returns":null,"REQUIRED":true}"
line: 1, col: 14352
at com.cedarsoftware.util.io.JsonReader.convertParsedMapsToJava(JsonReader.java:600)
at com.cedarsoftware.util.io.JsonReader.readObject(JsonReader.java:542)
at com.cedarsoftware.util.io.JsonReader.jsonToJava(JsonReader.java:289)
at com.cedarsoftware.util.io.JsonReader.jsonToJava(JsonReader.java:262)
at org.talend.components.api.properties.ComponentProperties.fromSerialized(ComponentProperties.java:155)
at org.talend.components.api.ComponentTestUtils.checkSerialize(ComponentTestUtils.java:34)
at org.talend.components.api.properties.PropertiesTest.testSerializeValues(PropertiesTest.java:57)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.junit.runner.JUnitCore.run(JUnitCore.java:160)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:117)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:234)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:74)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
Caused by: java.lang.ClassCastException: class org.talend.components.api.properties.Property$Flags != null
at java.util.EnumSet.typeCheck(EnumSet.java:398)
at java.util.RegularEnumSet.add(RegularEnumSet.java:161)
at java.util.RegularEnumSet.add(RegularEnumSet.java:36)
at com.cedarsoftware.util.io.ObjectResolver.traverseCollection(ObjectResolver.java:325)
at com.cedarsoftware.util.io.Resolver.convertMapsToObjects(Resolver.java:122)
at com.cedarsoftware.util.io.JsonReader.convertParsedMapsToJava(JsonReader.java:586)
... 34 more
JsonReader performs a method 'rehashMaps()' that invokes 'map.put(..)' which leads to an UnsupportedOperationException
Here is an example code:
HashMap<String, String> hsOurMap = new HashMap<>();
hsOurMap.put("key", "val");
String strJson = JsonWriter.objectToJson(Collections.unmodifiableMap(hsOurMap));
HashMap<String, String> clone = (HashMap<String, String>) JsonReader.jsonToJava(strJson);
A String will be serialized fine as simple String:
String strJson = JsonWriter.objectToJson("5");
=> "5"
But the json reader can not read this vice versa, it throws an Exception
String strClone = (String) JsonReader.jsonToJava(strJson);
Same Exception when formatting the string with
String strBeauty = JsonWriter.formatJson(strJson);
java.io.IOException: Input is invalid JSON; does not start with '{' or '[', c=34
Last read: "
line: 1, col: 2
at com.cedarsoftware.util.io.JsonReader.error(JsonReader.java:3203)
at com.cedarsoftware.util.io.JsonReader.readJsonObject(JsonReader.java:2213)
at com.cedarsoftware.util.io.JsonReader.readObject(JsonReader.java:1161)
at com.cedarsoftware.util.io.JsonReader.jsonToJava(JsonReader.java:1085)
Thus, we have to make a workaround for serializing/deserializing simple Strings. We are using json-io 2.6.1. We would be pleased if this could be fixed! Thanks a lot for this fine piece of work.
I'm using this library to serialize objects being passed between android applications. Since upgrading to Android 5, I'm now seeing a ClassNotFoundException when deserializing proxy objects. It makes sense that since the proxy object class is $Proxy1 it wouldn't be able to be instantiated by that name on the other side, but Proxy is a serializable class so there must be a way to do it.
Here is one example of a json payload that will cause the issue:
{
"@type":"android.os.Bundle",
"mAllowFds":true,
"mFdsKnown":true,
"mHasFds":false,
"mClassLoader":{
"@type":"java.lang.BootClassLoader",
"packages":{
"@type":"java.util.HashMap",
"com.android.org.conscrypt":{
"@type":"java.lang.Package",
"implTitle":"Unknown",
"implVendor":"Unknown",
"implVersion":"0.0",
"name":"com.android.org.conscrypt",
"sealBase":null,
"specTitle":"Unknown",
"specVendor":"Unknown",
"specVersion":"0.0"
}
},
"parent":null,
"proxyCache":{
"@type":"java.util.HashMap",
"@keys":[
{
"@type":"java.util.ArrayList",
"@Items":[
{
"@type":"class",
"value":"android.content.IContentProvider"
}
]
}
],
"@Items":[
{
"@type":"class",
"value":"$Proxy1"
}
]
}
},
"mMap":{
"invalidReason":"",
"areSecuritySettingsValid":true
},
"mParcelledData":null
}
Attempting to call .jsonToJava() on a JSON payload which contains an instance of android.net.Uri fails with the following exception:
Caused by: java.lang.UnsupportedOperationException at java.util.AbstractList.add(AbstractList.java:404) at java.util.AbstractList.add(AbstractList.java:425) at com.cedarsoftware.util.io.JsonReader.traverseCollection(JsonReader.java:1632) at com.cedarsoftware.util.io.JsonReader.convertMapsToObjects(JsonReader.java:1372) at com.cedarsoftware.util.io.JsonReader.convertParsedMapsToJava(JsonReader.java:1319) at com.cedarsoftware.util.io.JsonReader.readObject(JsonReader.java:1279) at com.cedarsoftware.util.io.JsonReader.jsonToJava(JsonReader.java:1170)
This is presumably due to the fact that android.net.Uri is an immutable class, and so when deserialization calls for values to be set on the created object this exception is raised. Is this a known bug and if so is there a workaround?
Hi,
Serializing singleton object is faulty in the current implementation of json io.
The readResolve function isn't called after the deserialization process.
Thanks in advance.
Hi.
I think that json provides a better way to represent a Map<String,V> than json-io uses.
Consider this demonstration:
public static void main(String args[]) throws ConfigurationException {
Map<String, Object> feedback = new LinkedHashMap<>();
String input[] = {"foo","bar","baz" };
for (String s : input) {
try {
feedback.put(s, doStuff(s));
} catch (Exception e) {
feedback.put(s, e);
}
}
System.out.println(JsonWriter.toJson(feedback));
}
private static Object doStuff(String s) throws Exception {
if ("bar".equals(s)){
return new XMLConfiguration();
} else {
throw new Exception("Error!");
}
}
...Which outputs this:
{"@type":"java.util.LinkedHashMap","@keys":["foo","bar","baz"],"@items":[{"@id":209,"@type":"java.lang.Exception","detailMessage":"Error!","cause":{"@ref":209},"stackTrace":{"@id":205,"@items":[]},"suppressedExceptions":{"@id":202,"@type":"java.util.Collections$UnmodifiableRandomAccessList"}},{"@id":4,"@type":"org.apache.commons.configuration.XMLConfiguration","document":null,"rootElementName":null,"publicID":null,"systemID":null,"documentBuilder":null,"validating":false,"schemaValidation":false,"attributeSplittingDisabled":false,"entityResolver":{"@type":"org.apache.commons.configuration.resolver.DefaultEntityResolver","registeredEntities":{"@type":"java.util.HashMap"}},"delegate":{"@id":177,"@type":"org.apache.commons.configuration.XMLConfiguration$XMLFileConfigurationDelegate","this$0":{"@ref":4},"org.apache.commons.configuration.AbstractHierarchicalFileConfiguration$FileConfigurationDelegate.this$0":{"@ref":4},"fileName":null,"basePath":null,"autoSave":false,"strategy":{"@type":"org.apache.commons.configuration.reloading.InvariantReloadingStrategy"},"reloadLock":{"@type":"org.apache.commons.configuration.Lock","name":"AbstractFileConfiguration","instanceId":1},"encoding":null,"sourceURL":null,"noReload":0,"fileSystem":{"@type":"org.apache.commons.configuration.DefaultFileSystem","log":{"@type":"org.apache.commons.logging.impl.Log4JLogger","name":"org.apache.commons.configuration.DefaultFileSystem"},"org.apache.commons.configuration.FileSystem.log":{"@type":"org.apache.commons.logging.impl.NoOpLog"},"optionsProvider":null},"store":{"@type":"java.util.LinkedHashMap"},"listDelimiter":",","delimiterParsingDisabled":false,"throwExceptionOnMissing":false,"substitutor":null,"log":{"@type":"org.apache.commons.logging.impl.NoOpLog"},"listeners":{"@type":"java.util.concurrent.CopyOnWriteArrayList","@items":[{"@ref":4}]},"errorListeners":{"@type":"java.util.concurrent.CopyOnWriteArrayList","@items":[{"@type":"org.apache.commons.configuration.AbstractConfiguration$2","this$0":{"@ref":177}},{"@ref":4}]},"lockDetailEventsCount":{},"detailEvents":0},"root":{"@id":174,"children":{"nodes":null,"namedNodes":null},"attributes":{"nodes":null,"namedNodes":null},"parent":null,"value":null,"reference":null,"name":null,"attribute":false},"rootNode":{"@ref":174},"listDelimiter":",","delimiterParsingDisabled":false,"throwExceptionOnMissing":false,"substitutor":null,"log":{"@type":"org.apache.commons.logging.impl.Log4JLogger","name":"org.apache.commons.configuration.XMLConfiguration"},"listeners":{"@type":"java.util.concurrent.CopyOnWriteArrayList"},"errorListeners":{"@type":"java.util.concurrent.CopyOnWriteArrayList"},"lockDetailEventsCount":{},"detailEvents":0},{"@id":201,"@type":"java.lang.Exception","detailMessage":"Error!","cause":{"@ref":201},"stackTrace":{"@ref":205},"suppressedExceptions":{"@ref":202}}]}
...Rendered here for your convenience (by @vbodurov's wonderful tool at http://www.bodurov.com/JsonFormatter/) :
Now, since I'm using json-io for debugging/logging, I'd rather this output be more like this...
...Of course, I just hand-edited the json string to lay it out like that. What I've done is represented the Map as an array of (json) objects, rather than an array of keys followed by and array of values.
I believe that right around https://github.com/jdereg/json-io/blob/master/src/main/java/com/cedarsoftware/util/io/JsonWriter.java#L1379 is the spot to make this change, but since I am sure this proposal would break deserialization, I thought I'd check with you first. :)
What do you think? Is there a way to do this right? Is it a good thing to do? Can it be used for Map<K,V>, not just Map<String,V> ?
Thanks, cheers,
--Dave
I am working on a code base that someone else wrote, so I don't have any control over how friendly the objects are to the default settings of the java-based json serialzers/deserializers out there. So far, json-io has been the easiest to get this working for the code base. I've been making progress toward json coverage for all of the objects to be serialized, and yesterday I ran into a class that did not serialize/deserialize using the default json-io settings.
This class, SpanMap, is referenced below. It "implements" Map, but doesn't do a complete job (which may be the problem). Its intention is to dynamically support dereferencing of Map values from a backing store. Perhaps the class should have not implemented Map. But serialize I must.
I wrote some JsonClass...Ex code for this class, and the writer seems to be working fine. I followed the example from your github website.
writerExMap[SpanMap.class] = new JsonWriter.JsonClassWriterEx() {
void write(Object obj, boolean showType, Writer output, Map<String, Object> args) throws IOException {
SpanMap spanMap = (SpanMap) obj
output.write('"totalSize":')
output.write(String.valueOf(spanMap.getTotalSize()))
output.write(', "spanDir":"')
output.write(spanMap.getSpanDir())
output.write('", "spanKey":')
JsonWriter writer = JsonWriter.JsonClassWriterEx.Support.getWriter(args)
writer.writeImpl(spanMap.getSpanKey(), true)
output.write(', "map":')
writer.writeImpl(spanMap.getMap(), true)
}
}
This JsonClassWriterEx subclass produces the following json, which is the expected output for the provided SpanMap.
{
"@type": "java.util.concurrent.ConcurrentHashMap",
"Credential": {
"@type": "com.tlabs.datastore.index.SpanHistoryIndex",
"map": **{
"@type": "com.tlabs.datastore.spanmap.SpanMap",
"totalSize": 0,
"spanDir": "index/span/Credential/",
"spanKey": {
"@type": "com.tlabs.datastore.spanmap.SimpleSpanKey",
"limit": 20000
},
"map": {
"@type": "java.util.concurrent.ConcurrentSkipListMap"
}
}
}
}
My attempt to read (deserialize) this json, however, is not working.
The code below is my attempt to instrument what's going on.
readerExMap[SpanMap.class] = new JsonReader.JsonClassReaderEx() {
Object read(Object jOb, Deque<JsonObject<String, Object>> stack, Map<String, Object> args) {
JsonObject jObj = (JsonObject) jOb
SpanMap spanMap = new SpanMap()
JsonObject totalSize = jObj.get("totalSize")
log.info("################jObj...")
log.info(jObj.toString())
log.info("################jObj...")
spanMap.setTotalSize(totalSize.getPrimitiveValue())
JsonObject spanDir = jObj.spanDir
spanMap.setSpanDir(spanDir.getPrimitiveValue())
JsonReader reader = JsonReader.JsonClassReaderEx.Support.getReader(args)
JsonObject spanKeyRef = jObj.spanKey
JsonObject spanKeyTarget = reader.getRefTarget(spanKeyRef)
spanMap.setSpanKey(spanKeyTarget.get("spanKey"))
JsonObject spanMapRef = jObj.spanMap
JsonObject spanMapTarget = reader.getRefTarget(spanMapRef)
return spanMap
}
}
The code shows that I do not understand how reading works. I tried different things as you can see and inspected values using the IntelliJ debugger. There are few code examples online, and the ones that are there have not been enough for me to get past this. Probably my problem. But still a problem.
The IntelliJ debugger shows, for example, that jObj.get("totalSize") returns null. I tried other things, but failed to access the "totalSize" field which, as you can see, is in the json string. More generally, I haven't been able to figure out how to pull values from the JsonObject without interrogating the structure shown below directly with array. I've inspected the JsonObject using IntelliJ, trying all of the documented methods. I'm definitely not understanding how reading works.
The output below is the result of logging jObj.toString(). You can see that it does not match the json listed above. For example, there is no type information for "spanKey" or "map", which are not scalar fields.
jObj = {com.cedarsoftware.util.io.JsonObject@1525} size = 4
0 = {java.util.LinkedHashMap$Entry@2862} "@keys" ->
key = {java.lang.String@2614} "@keys"
value = {java.lang.Object[4]@2864}
0 = {java.lang.String@2870} "totalSize"
1 = {java.lang.String@2871} "spanDir"
2 = {java.lang.String@2872} "spanKey"
3 = {java.lang.String@2873} "map"
1 = {java.util.LinkedHashMap$Entry@2863} "@items" ->
key = {java.lang.String@2615} "@items"
value = {java.lang.Object[4]@2802}
0 = {java.lang.Long@2803} "0"
1 = {java.lang.String@2804} "index/span/Credential/"
2 = {com.cedarsoftware.util.io.JsonObject@2805} size = 1
0 = {java.util.LinkedHashMap$Entry@2832} "limit" -> "20000"
key = {java.lang.String@2833} "limit"
value = {java.lang.Long@2834} "20000"
3 = {com.cedarsoftware.util.io.JsonObject@2806} size = 0
Questions:
This is a long post, but this is what it took to feel like I halfway described what's going on. Maybe an example would help? The bit about the JsonObject not matching the json string has me a bit worried. That said, I'm hoping to successfully deserialize in the not too distant future (using json-io).
Thanks!
-- Gary
This is useful in a version migration situation where the current version of a class want's to handle a previously serialized version that contains a field that was removed in the current version.
A pull request will be provided.
I have an enum like:
public enum AssetType {
ABSTRACT(AssetEncoding.CONTENT_ENCODING),
AUTOCOMPLETE(AssetEncoding.CONTENT_ENCODING),
...
private EnumSet<AssetEncoding> encoding;
private AssetType(EnumSet<AssetEncoding> encoding) {
this.encoding = encoding;
}
...
}
The emitted JSON for this enum includes information about the "encoding" private field as follows:
"x" : {
"@id": 1548,
"@type": "com.uptodate.web.api.AssetType",
"encoding": {
"@id": 60,
"@type": "java.util.RegularEnumSet",
"@items": [
{
"@type": "com.uptodate.web.api.AssetEncoding",
"name": "COMPRESSED",
"ordinal": 0
},
{
"@type": "com.uptodate.web.api.AssetEncoding",
"name": "ENCRYPTED",
"ordinal": 1
},
{
"@type": "com.uptodate.web.api.AssetEncoding",
"name": "BASE64",
"ordinal": 2
},
{
"@type": "com.uptodate.web.api.AssetEncoding",
"name": "JSON",
"ordinal": 3
}
]
},
"name": "TOPIC",
"ordinal": 10
},
This causes the following exception when passed to "toJava"
java.lang.ClassCastException: class com.uptodate.web.api.AssetEncoding != null
at java.util.EnumSet.typeCheck(Unknown Source)
at java.util.RegularEnumSet.add(Unknown Source)
at java.util.RegularEnumSet.add(Unknown Source)
at com.cedarsoftware.util.io.JsonReader.traverseCollection(JsonReader.java:1587)
at com.cedarsoftware.util.io.JsonReader.convertMapsToObjects(JsonReader.java:1286)
at com.cedarsoftware.util.io.JsonReader.traverseCollection(JsonReader.java:1585)
at com.cedarsoftware.util.io.JsonReader.convertMapsToObjects(JsonReader.java:1286)
at com.cedarsoftware.util.io.JsonReader.traverseCollection(JsonReader.java:1585)
at com.cedarsoftware.util.io.JsonReader.convertMapsToObjects(JsonReader.java:1286)
at com.cedarsoftware.util.io.JsonReader.convertParsedMapsToJava(JsonReader.java:1233)
at com.cedarsoftware.util.io.JsonReader.readObject(JsonReader.java:1193)
at com.cedarsoftware.util.io.JsonReader.jsonToJava(JsonReader.java:1085)
I am surprised to see the emitted JSON contain the enum's "ordinal" value and the enum's private fields. I would expect to see just the name:
"x" : {
"@id": 1548,
"@type": "com.uptodate.web.api.AssetType",
"name": "TOPIC",
},
GSON for example emits just the name:
"x" : "TOPIC"
2.7.0 on Linux
Please provide any additional information below.
I can work around the problem by declaring my enum fields "transient". That would not work for third-party software obviously, so I think the tool would be better if it handled this situation properly.
That's it. I've had no other problems, it is a great library! Thank you.
We are working in an OSGi environment and in the case where a @type class cannot be loaded, a LinkedHashMap is created instead and then it gets an error when it tries to assign that object. This was difficult to debug. There should be a clear error indicating the type not found which would make this problem easier to track.
PR is coming to address this.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.