Giter Club home page Giter Club logo

json-io's People

Contributors

bhe-talendbj avatar bmbanker avatar darabos avatar darmbrust avatar daveloyall avatar dependabot[bot] avatar devlynnx avatar dtracers avatar frabert avatar h143570 avatar jdereg avatar jsnyder4 avatar kaihufenbach avatar kpartlow avatar lance0428 avatar laurgarn avatar lightcycle avatar lordvlad avatar mhmxs avatar ozhelezniak-talend avatar pedrocpneto avatar pwntester avatar reuschling avatar senich avatar sgandon avatar thomasx avatar twillouer avatar wwang-talend avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

json-io's Issues

Serialized simple string can not be deserialized by JsonReader

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.

java.lang.VerifyError with 2.9.2 and Android < 5.0

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)

Maybe unnecessary call of convertParsedMapsToJava inside JsonReader.readObject()

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;
}

possible issue

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.

NullPointer when writing 2 objects

Version

Concerns version json-io-2.6.0.

Issue

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.

How to reproduce

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)

Question

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?

Provide a callback for missing fields

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.

Deserealize list of data

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)

Could not instantiate java.net.URL using any constructor during JsonReader.jsonToJava

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);
    }
}

UnmodifiableMap can not be deserialized

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);

Add support for replacement at the field level.

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.

About performance

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?

own member variables in subclasses of Map will not be considered during serialization

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.

Gracefully omit fields

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?

json emitted for enum includes private fields, causes error when parsing

What steps will reproduce the problem?

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)

What is the expected output? What do you see instead?

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"

What version of the product are you using? On what operating system?

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.

Disable @ref

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!

Empty EnumSet can't be used after being deserialized

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.

@type not outputed for all data types

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,

support jdk 6

at the moment the library does not work with jdk 6

Error deserializing android.net.Uri

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?

add a backlist of field not to be serialized

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.

ClassNotFoundException while deserializing Proxied objects

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
}

Class file not compatible with older versions of Java

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.

Question re: json representation of Map<String,V>

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/) :
image

Now, since I'm using json-io for debugging/logging, I'd rather this output be more like this...
image

...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

typos in README.md

Object obj = JsonReader.jsonToJava(json, [(JsonReader.USE_MAPS): true)]) extra paren
Employee emp = (Employee) JsonReader.jsonToJava(stream); extra equals

Problem deserializing ObservableObjects

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?

Possible to omit "@type" property when writing?

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.

NaN, Infinity, -Infinity is not supported

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}

JsonObject.getArray VS Object[]

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?

deserialization of objects

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.

json format for associative array / map

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).

Cannot add a custom writer for an interface

Use case:

  • field type is an interface type (e.g. CharSequence);
  • I don't want to preserve the concrete class of the value (it can be complicated and heavyweight, something like WordProcessorMainWindowSpan);
  • I inherit a custom writer from JsonStringWriter and write value.toString() as a primitive String;
  • I call addWriter(CharSequence.class, myCustomWriter).
    Expected:
  • value is serialized and retrieved as String;
    Actual:
  • writer is not recognized because no superclass matches CharSequence.

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).

strange ArrayIndexOutOfBoundsException during deserialization, depending on type parameters

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.

EnumSet not supported

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

Unclear error when failing to load a class sometimes

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.

custom reader questions

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:

  1. Why does the first argument supplied to JavaClassReaderEx.read() not contain all of the information in the json string?
  2. How does one access the elements in the supplied JsonObject? I thought I'd be able to access them using a Map-like accessor and cast the Object result to the desired SpanMap variable type.

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

Nested template support in Collection<T> and Map<K, V>

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.

json-io fails for any immutable map implementation

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)

Cannot deserialize type with generics

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

JsonWriter Fails to Write a Map with Long Keys

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());

FIELD_SPECIFIERS does not allow subclasses field to be serialized

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.

Feature request: add an optional fallback type parameter for the toplevel json container to JsonReader.jsonToJava(json);

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

Provide a means of automatically reading an object with a custom reader

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.

Failed to deserialize immutable Collections.SingletonMap

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

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.