Git Product home page Git Product logo

logansquare's Introduction

Android Arsenal Android Weekly Travis Build

#LoganSquare

The fastest JSON parsing and serializing library available for Android. Based on Jackson's streaming API, LoganSquare is able to consistently outperform GSON and Jackson's Databind library by 400% or more1. By relying on compile-time annotation processing to generate code, you know that your JSON will parse and serialize faster than any other method available.

By using this library, you'll be able to utilize the power of Jackson's streaming API without having to code tedius, low-level code involving JsonParsers or JsonGenerators. Instead, just annotate your model objects as a @JsonObject and your fields as @JsonFields and we'll do the heavy lifting for you.

Don't believe it could improve upon Jackson Databind's or GSON's performance that much? Well, then check out the nifty graphs below for yourself. Not convinced? Feel free to build and run the BenchmarkDemo app included in this repository.

1 Note: Our "400% or more" performance improvement metric was determined using ART. While LoganSquare still comes out on top with Dalvik, it seems as though the comparison is much closer. The benchmarks shown are actual screenshots taken from a 2nd gen Moto X.

Benchmarks

##Download

Note that Gradle is the only supported build configuration for LoganSquare. To add the library to your app's build.gradle file.

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
    }
}
apply plugin: 'com.neenbedankt.android-apt'

dependencies {
    apt 'com.bluelinelabs:logansquare-compiler:1.3.6'
    compile 'com.bluelinelabs:logansquare:1.3.6'
}

For the curious, the buildscript and apply plugin lines add the apt plugin, which is what allows us to do compile-time annotation processing. The first dependency is what tells Gradle to process your JSON annotations, and the second dependency is our tiny 19kb runtime library that interfaces with the generated code for you.

##Usage

Using LoganSquare is about as easy as it gets. Here are a few docs to get you started:

##Proguard Like all libraries that generate dynamic code, Proguard might think some classes are unused and remove them. To prevent this, the following lines can be added to your proguard config file.

-keep class com.bluelinelabs.logansquare.** { *; }
-keep @com.bluelinelabs.logansquare.annotation.JsonObject class *
-keep class **$$JsonObjectMapper { *; }

##Why LoganSquare?

We're BlueLine Labs, a mobile app development company based in Chicago. We love this city so much that we named our company after the blue line of the iconic 'L.' And what's one of the most popular stops on the blue line? Well, that would be Logan Square of course. Does it have anything to do with JSON? Nope, but we're okay with that.

##Props

##License

Copyright 2015 BlueLine Labs, Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

logansquare's People

Contributors

erickuck avatar mannodermaus avatar mariotaku avatar ppamorim avatar ralscha avatar ronocod avatar talklittle avatar trevjonez 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  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

logansquare's Issues

Question: Is is possible to parse/serialize to/from java.util.Map?

Hi,

I'd like to serialize/parse between java.util.Map and JSON string. And following codes don't work because I did not set annotations. Is is possible to parse/serialize to/from java.util.Map? If yes, how can I do it?

Serialize

Map<String, Object> map = new HashMap<String,Object>();
map.put("key", 1);
String json = LoganSquare.serialize(map);

Parse

String json = "{\"key\":1}";
Map<String, Object> map = LoganSquare.parse(json, Map.class);

Thanks,

Null-values skipped in nested list

I noticed an issue where in a (nested) list the null values are skipped, The list in the following json example has only 9 values instead of 10.

@JsonObject
public class ApiCursor {
    @JsonField(name="Columns")
    private ArrayList<String> columns;

    @JsonField(name="Rows")
    private ArrayList<ArrayList<String>> rows;

    public ArrayList<String> getColumns() {
        return columns;
    }

    public void setColumns(ArrayList<String> columns) {
        this.columns = columns;
    }

    public ArrayList<ArrayList<String>> getRows() {
        return rows;
    }

    public void setRows(ArrayList<ArrayList<String>> rows) {
        this.rows = rows;
    }
}
{
    "Rows": [
        [
            "value1",
            "value2",
            "value2",
            "value3",
            "value4",
            "value5",
            "value6",
            "value7",
            null,
            "value9",
            "value10"
        ]
    ],
    "Columns": [
        "column1",
        "column2",
        "column3",
        "column4",
        "column5",
        "column6",
        "column7",
        "column8",
        "column9",
        "column10",
        "column11"
    ]
}

DexException when adding the library to build.gradle

Hi. I added LoganSquare to my app's build.gradle file as described in the Download section on your main Github page. When I build my project, the build fails and I get this error:

UNEXPECTED TOP-LEVEL EXCEPTION:
com.android.dex.DexException: Multiple dex files define Lcom/fasterxml/jackson/core/Base64Variant;
        at com.android.dx.merge.DexMerger.readSortableTypes(DexMerger.java:594)
        at com.android.dx.merge.DexMerger.getSortedTypes(DexMerger.java:552)
        at com.android.dx.merge.DexMerger.mergeClassDefs(DexMerger.java:533)
        at com.android.dx.merge.DexMerger.mergeDexes(DexMerger.java:170)
        at com.android.dx.merge.DexMerger.merge(DexMerger.java:188)
        at com.android.dx.command.dexer.Main.mergeLibraryDexBuffers(Main.java:439)
        at com.android.dx.command.dexer.Main.runMonoDex(Main.java:287)
        at com.android.dx.command.dexer.Main.run(Main.java:230)
        at com.android.dx.command.dexer.Main.main(Main.java:199)
        at com.android.dx.command.Main.main(Main.java:103)

Here's my list of dependencies in my build.gradle file:

dependencies {
    compile 'com.bluelinelabs:logansquare-compiler:1.0.6'
    compile 'com.bluelinelabs:logansquare:1.0.6'
    compile 'com.android.support:support-v4:18.0.+'
    compile 'com.android.support:appcompat-v7:18.0.+'
    compile 'com.viewpagerindicator:library:2.4.2-SNAPSHOT'
    compile 'com.commonsware.cwac:merge:1.0.1'
    compile files('libs/libGoogleAnalyticsV2.jar')
    compile files('libs/aws-android-sdk-2.1.1-core.jar')
    compile files('libs/aws-android-sdk-2.1.1-s3.jar')
    compile('com.crashlytics.sdk.android:crashlytics:2.0.1@aar') {
        transitive = true;
    }

java.lang.StackOverflowError when processing

Hi

I just stuck @JsonObject/@JsonField on a .. ton of classes, and compiling now I get:

error: Exception while processing Json classes. Stack trace incoming:
  java.lang.StackOverflowError
    at com.squareup.javapoet.ClassName.<init>(ClassName.java:43)
    at com.squareup.javapoet.ClassName.get(ClassName.java:165)
    at com.squareup.javapoet.TypeName$1.visitDeclared(TypeName.java:132)
    at com.squareup.javapoet.TypeName$1.visitDeclared(TypeName.java:107)
    at com.sun.tools.javac.code.Type$ClassType.accept(Type.java:936)
    at com.squareup.javapoet.TypeName.get(TypeName.java:107)
    at com.squareup.javapoet.TypeVariableName.get(TypeVariableName.java:88)
    at com.squareup.javapoet.TypeName$1.visitTypeVariable(TypeName.java:147)
    at com.squareup.javapoet.TypeName$1.visitTypeVariable(TypeName.java:107)
    at com.sun.tools.javac.code.Type$TypeVar.accept(Type.java:1319)
    at com.squareup.javapoet.TypeName.get(TypeName.java:107)
    at com.squareup.javapoet.TypeName$1.visitDeclared(TypeName.java:137)
    at com.squareup.javapoet.TypeName$1.visitDeclared(TypeName.java:107)
    at com.sun.tools.javac.code.Type$ClassType.accept(Type.java:936)
    at com.squareup.javapoet.TypeName.get(TypeName.java:107)
    at com.squareup.javapoet.TypeVariableName.get(TypeVariableName.java:88)
    at com.squareup.javapoet.TypeName$1.visitTypeVariable(TypeName.java:147)
    at com.squareup.javapoet.TypeName$1.visitTypeVariable(TypeName.java:107)
    at com.sun.tools.javac.code.Type$TypeVar.accept(Type.java:1319)

And so on... Now it wouldn't surprise me if the problem exists in my code, consider this bug report a bug report on the not so helpful error message. Maybe some debug mode can be supported that prints out which classes it's currently working on?

Could not be mapped to a JSONObject Exception

I get the following error when trying to parse an object to JSON

com.bluelinelabs.logansquare.NoSuchMapperException: Class io.realm.ShotRealmProxy could not be mapped to a JSON object. Perhaps it hasn't been annotated with @JsonObject?
            at com.bluelinelabs.logansquare.LoganSquare.mapperFor(LoganSquare.java:171)
            at com.bluelinelabs.logansquare.LoganSquare.serialize(LoganSquare.java:100)

I use Realm as the underlying database and the object I am trying to parse is a model class which extends RealmObject class. The model class has been annotated with @JsonObject but looking at the error I think its trying to convert the Base class which in my case is the generated class by Realm. Any ideas as to what can be done ?

Add better error messages

Currently a bunch of error conditions just spit out a stack trace because they aren't explicitly handled. If you know of a specific condition like this, please post it here so we can get them all handled.

Wrapped objects

I've already seen the generics issue #24 , this one is a little similar

I get a wrappen object

{ foo : { bar : "" , bar2 : ""}}

The same wrapped format for lists of this object

[ {foo : { bar : "" , bar2 : ""}}, {foo : { bar : "" , bar2 : ""}}]

It would be nice to have an option to enable the removal of those wrapping elements, e.g. boolean flag defaults to false, if enabled it will just skip the wrapping element completely.

_parse(JsonParser jsonParser) throws IOException {
    // .....
    if (jsonParser.getCurrentToken() != JsonToken.START_OBJECT) {
        jsonParser.skipChildren();
        return null;
    }
    // e.g. just add the following lines, not tested
    jsonParser.nextToken();
    while(jsonParser.getCurrentToken() != JsonToken.START_OBJECT )
        jsonParser.nextToken();
    // .....
}

Don't process fields marked as "static" and/or "transient"

It's standard behavior for other json parsers to skip fields with static and transient
See a small model class below, with its generated code.

import com.bluelinelabs.logansquare.annotation.JsonIgnore;
import com.bluelinelabs.logansquare.annotation.JsonObject;

@JsonObject(fieldDetectionPolicy = JsonObject.FieldDetectionPolicy.NONPRIVATE_FIELDS)
public class Test {
    public transient String transientString;
    public static final String staticString;
    public static final Parcelable.Creator<Test> CREATOR = new Parcelable.Creator<Test>() {
        @Override
        public Test createFromParcel(Parcel source) {
            return new Test();
        }

        @Override
        public Test[] newArray(int size) {
            return new Test[size];
        }
    };
}

generated code:

public static void parseField(Test instance, String fieldName, JsonParser jsonParser) throws IOException {
    if ("transientString".equals(fieldName)) {
      instance.transientString = jsonParser.getValueAsString(null);
    } else if ("staticString".equals(fieldName)){
      instance.staticString = jsonParser.getValueAsString(null);
    } else if ("CREATOR".equals(fieldName)){
      instance.CREATOR = LoganSquare.typeConverterFor(android.os.Parcelable.Creator<Test>.class).parse(jsonParser);
    }
  }

public static void _serialize(Test object, JsonGenerator jsonGenerator, boolean writeStartAndEnd) throws IOException {
    if (writeStartAndEnd) {
      jsonGenerator.writeStartObject();
    }
    jsonGenerator.writeStringField("transientString", object.transientString);
    jsonGenerator.writeStringField("staticString", object.staticString);
    if (object.CREATOR != null) {
      LoganSquare.typeConverterFor(Parcelable.Creator<Test>.class).serialize(object.CREATOR, "CREATOR", true, jsonGenerator);
    }
    if (writeStartAndEnd) {
      jsonGenerator.writeEndObject();
    }
  }

Thread safety

Hi. I'm considering to use this library in our product. I have read some part of the implementation and I noticed that this library is not thread-safe for now.


First, the implementation of the LoganSquare.TYPE_CONVERTERS field is like the following;

private static final Map<Class, TypeConverter> TYPE_CONVERTERS = new HashMap<Class, TypeConverter>();

Should be;

private static final Map<Class, TypeConverter> TYPE_CONVERTERS = new ConcurrentHashMap<Class, TypeConverter>();

Second, the implementation of the LoganSquare.mapperFor() method is like the following;

public static <E> JsonMapper<E> mapperFor(Class<E> cls) throws NoSuchMapperException {
    JsonMapper<E> mapper = OBJECT_MAPPERS.get(cls);

    if (mapper == null) {
        try {
            Class<?> mapperClass = Class.forName(cls.getName() + Constants.MAPPER_CLASS_SUFFIX);
            mapper = (JsonMapper<E>)mapperClass.newInstance();
            OBJECT_MAPPERS.put(cls, mapper);
        } catch (Exception e) {
            throw new NoSuchMapperException(cls, e);
        }
    }

    return mapper;
}

Should be;

public static <E> JsonMapper<E> mapperFor(Class<E> cls) throws NoSuchMapperException {
    synchronized (OBJECT_MAPPERS) {
        JsonMapper<E> mapper = OBJECT_MAPPERS.get(cls);

        if (mapper == null) {
            try {
                Class<?> mapperClass = Class.forName(cls.getName() + Constants.MAPPER_CLASS_SUFFIX);
                mapper = (JsonMapper<E>)mapperClass.newInstance();
                OBJECT_MAPPERS.put(cls, mapper);
            } catch (Exception e) {
                throw new NoSuchMapperException(cls, e);
            }
        }

        return mapper;
    }
}

Is that all to make this library thread-safe?

Thanks,
Haruki Hasegawa

Comparison to ig-json-parser?

I see you guys are comparing it to GSON and Jackson, but have you thought in comparing it with another Jackson based code generation thingy like ig-json-parser?

Support standartized annotations

Thanks for creating such awesome library! It would have been even better if it had at least partial support for some standardized annotations (such as Jax-Rs 2 bean annotations). Such support would greatly increase interoperability and make using it in existing projects much less of hassle.

NoSuchMapperException

Hi,

I 've just discovered this library and want to rewrite my code to avoid usin the Gson .

But I got this error

03-23 18:36:20.532 2071-2092/u.a D/A [com.u.Networks.Http.Requests.RequestGson]﹕ [
{
"table": "glycemies",
"version": 2
}
]
03-23 18:36:20.544 2071-2092/u.a W/dalvikvm﹕ dvmFindClassByName rejecting '[Lu.a.Api.Models.ModelSyncTableStatus;$$JsonObjectMapper'
03-23 18:36:20.552 2071-2092/u.a E/Volley﹕ [109] NetworkDispatcher.run: Unhandled exception com.bluelinelabs.logansquare.NoSuchMapperException: Class u.a.Api.Models.ModelSyncTableStatus[] could not be mapped to a JSON object. Perhaps it hasn't been annotated with @JsonObject?
com.bluelinelabs.logansquare.NoSuchMapperException: Class u.a.Api.Models.ModelSyncTableStatus[] could not be mapped to a JSON object. Perhaps it hasn't been annotated with @JsonObject?
at com.bluelinelabs.logansquare.LoganSquare.mapperFor(LoganSquare.java:171)
at com.bluelinelabs.logansquare.LoganSquare.parse(LoganSquare.java:50)
at com.u.Networks.Http.Requests.RequestGson.parseNetworkResponse(RequestGson.java:155)
at com.android.volley.NetworkDispatcher.run(NetworkDispatcher.java:123)
Caused by: java.lang.ClassNotFoundException: [Lu.a.Api.Models.ModelSyncTableStatus;$$JsonObjectMapper
at java.lang.Class.classForName(Native Method)
at java.lang.Class.forName(Class.java:217)
at java.lang.Class.forName(Class.java:172)
at com.bluelinelabs.logansquare.LoganSquare.mapperFor(LoganSquare.java:167)
            at com.bluelinelabs.logansquare.LoganSquare.parse(LoganSquare.java:50)
            at com.u.Networks.Http.Requests.RequestGson.parseNetworkResponse(RequestGson.java:155)
            at com.android.volley.NetworkDispatcher.run(NetworkDispatcher.java:123)
03-23 18:36:20.844 2071-2096/u.a I/A [u.a.Syncronisation.SyncAdapter]﹕ WTF: java.util.concurrent.ExecutionException: com.android.volley.VolleyError: com.bluelinelabs.logansquare.NoSuchMapperException: Class u.a.Api.Models.ModelSyncTableStatus[] could not be mapped to a JSON object. Perhaps it hasn't been annotated with @JsonObject?

Then my class is like this :

package u.a.Api.Models;

import com.bluelinelabs.logansquare.annotation.JsonField;
import com.bluelinelabs.logansquare.annotation.JsonObject;
//import com.google.gson.annotations.Expose;
//import com.google.gson.annotations.SerializedName;
@JsonObject
public class ModelSyncTableStatus {
@JsonField
public String table;
@JsonField
public int version;

Can you help me ?

Allow constructor injection.

Oftentimes you want your model object to be immutable so you don't want to make your fields public or provide setters. Would it be possible to support constructor injection for this usecase? Something like:

@JsonObject
public class Image {

    @JsonField(name = "_id")
    private int imageId;

    @JsonField
    private String format;

    @JsonField
    private String url;

    @JsonField
    private String description;

    @JsonField(name = "similar_images")
    private List<Image> similarImages;

   // Not sure if the arguments need to be annotated instead/as well.
   @JsonConstructor
   public Image(int imageId, String format, String url, String description, List<Image> similarImages) {
       this.imageId = imageId;
       this.format = foramt;
       this.url = url;
       this.description = description;
       this.similarImages = similarImages;
   }

   public int getImageId() {
      return getImageId;
   }

   public String getFormat() {
      return format;
   }

   public String getUrl() {
      return url;
   }

   public List<Image> getSimilarImages() {
      return Collections.unmodifiableList(similarImages);
   }
}

Parse: File, URL, Reader, byte[], char[]

Would be nice to be able to LoganSquare.parse() from the different sources allowed by Jackson's JsonFactory.

JsonFactory provides all of the following:

  • createParser(File)
  • createParser(URL)
  • createParser(InputStream)
  • createParser(Reader)
  • createParser(byte[])
  • createParser(byte[], int, int)
  • createParser(String)
  • createParser(char[])
  • createParser(char[], int, int)

Any way to support non named JSON Arrays ?

I know this may be far fetched, but I was wondering if there is any way Logan Square could support parsing JSON Arrays without a key.

Ex : Consider the JSON response from Dribbble below -

[
{
"id": 471756,
"title": "Sasquatch",
"description": "

Quick, messy, five minute sketch of something that might become a fictional something.

",
"width": 400,
"height": 300,
}
]

The response can be found documented here - http://developer.dribbble.com/v1/shots/#list-shots

So now, is there any way we could parse the outer array which doesn't have a key ?

Date converter does not work when running on Robolectric

Actually, this is not an issue of LoganSquare. I noticed that the DefaultDateConverter does not work when running on Robolectric.

Running on Android:

SimpleDateFormat accepts these format for the "Z" place holder: Z/ZZ/ZZZ:-0800 ZZZZ:GMT-08:00 ZZZZZ:-08:00
ref.) http://developer.android.com/reference/java/text/SimpleDateFormat.html

Running on Robolectric (JRE):

SimpleDateFormat only accepts "-0800" format for the "Z" place holder. Should use "X" place holder for ISO 8601 format.
ref.) http://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html#rfc822timezone


Proposed fix:

Use +0000 in the DefaultDateFormatter.getFixedInputString() method. This works on both Android and JRE.

public class DefaultDateFormatter extends SimpleDateFormat {
    /** Replace ending Z's with +0000 so Java's SimpleDateFormat can handle it correctly */
    private String getFixedInputString(String input) {
        return input.replaceAll("Z$", "+0000");
    }
}

Support for generic classes

The majority of our JSON objects in our API responses are wrapped inside of a base object (meta/results), so we have a generic class to pass back results of any type. I've found the JsonObject annotation can't be used on generics. Any chance this can be supported at some point?

Read map of objects

I noticed a lack of support to deserialize maps, as i was trying to parse the following input

{ "journey1" : { } , 
  "journey2" : { }
}

to

HashMap<String,V0Journey>

Allow private fields

It would be nice to provide encapsulation for @JsonField class members.

I've been struggling with the proper way to implement this same issue in Ollie, and I think an ideal solution would be for the processor to require get/set methods corresponding to private fields using naming conventions.

Thoughts?

JsonIgnore annotation seems to be broken

This model class:

import com.bluelinelabs.logansquare.annotation.JsonIgnore;
import com.bluelinelabs.logansquare.annotation.JsonObject;

@JsonObject(fieldDetectionPolicy = JsonObject.FieldDetectionPolicy.NONPRIVATE_FIELDS_AND_ACCESSORS)
public class Test {
    public String shouldBeProcessed;
    @JsonIgnore
    public String shouldNotBeProcessed;
}

Generates this code for me:

public static void parseField(Test instance, String fieldName, JsonParser jsonParser) throws IOException {
    if ("shouldBeProcessed".equals(fieldName)) {
      instance.shouldBeProcessed = jsonParser.getValueAsString(null);
    } else if ("shouldNotBeProcessed".equals(fieldName)){
      instance.shouldNotBeProcessed = jsonParser.getValueAsString(null);
    }
  }

public static void _serialize(Test object, JsonGenerator jsonGenerator, boolean writeStartAndEnd) throws IOException {
    if (writeStartAndEnd) {
      jsonGenerator.writeStartObject();
    }
    jsonGenerator.writeStringField("shouldBeProcessed", object.shouldBeProcessed);
    jsonGenerator.writeStringField("shouldNotBeProcessed", object.shouldNotBeProcessed);
    if (writeStartAndEnd) {
      jsonGenerator.writeEndObject();
    }
  }

Adding the ability to create multiple instance of the LoganSquare object

A nice feature of GSON is to be able to register different type of adapter on different instance of the Gson object. -- For some obvious performance reason, the app have to keep a singleton of the created object but could be quickly done by a factory pattern.

Essentially that help when you need to deserialize / serialize an object in a different way.
What do you think?

Support parceble

Hello.
I am just currios if it can be not a serialisable, but parceble instead?
There is already a sweat library, which makes any object a parceble https://github.com/sockeqwe/ParcelablePlease and I just wondering if you can extend your library... Probably I am too lazy. Still you library is great.

Use registered TypeConverters when parsing fields

If there is a registered TypeConverter for a given class ThatClass, a nested field of type ThatClass should first try using the registered TypeConverter when parsing, instead of immediately using ThatClass$$JsonObjectMapper._parse()

Example:

@JsonObject
public class Something {
    @JsonField ThatClass thatVar;
}

@JsonObject
public class ThatClass {
    @JsonField int blah;
}

public class ThatClassTypeConverter implements TypeConverter<ThatClass> {
    // ...
}

LoganSquare.registerTypeConverter(ThatClass.class, new ThatClassTypeConverter());

// ***Ideally use ThatClassTypeConverter instead of ThatClass$$JsonObjectMapper._parse()***
LoganSquare.parse(is, Something.class);

Add support for alternative JSON [de/]serializers

A hard dependency on Jackson makes this project difficult to adopt in existing large projects or ones that are sensitive to dependencies. In particular, an option to use Android's built-in JsonReader parser would be very handy.

A modular design that allowed custom code generators (or sufficient hooking in the standard generator) would be greatly preferred as it is technically possible to build a custom JSON parser that will outperform Jackson for your particular use case. Specifically, Jackson creates many internal unnecessary objects because it doesn't have strong awareness of what concrete target type the JSON type is going to fit into. With this knowledge in the parser generator, primitives (including strings) can be constructed with less object overhead.

Add support for nested collection types

This may be similar to #11. Feel free to close this and only keep the other one if that makes sense

The specific case I'm trying to get solved is:

public Map<String, List<MyObject>> myObjectsById

In parseField(), this currently turns into (with compiler error "Cannot select from parameterized type")

map.put(key, LoganSquare.typeConverterFor(java.util.List<MyObject>.class).parse(jsonParser));

This would work instead:

map.put(key, LoganSquare.mapperFor(MyObject.class).parseList(jsonParser));

Benchmarks are affected by Gson and Jackson initialization

Each time an object is parsed or serialized using Gson or Jackson in the benchmarks, a new instance of the Gson or ObjectMapper class is created. These objects are often cached and reused in real-world applications so the benchmarks don't reflect the normal performance of Gson and Jackson.

LoganSquare still performs the best out of the 3 libraries when the caching is used, but by a much smaller margin:
screenshot_2015-02-23-10-30-28

NoSuchMapperException

Hi,

I am trying to serialize a collection to json, but while doing that getting following exception

"Class java.util.ArrayList could not be mapped to a JSON object. Perhaps it hasn't been annotated with @JsonObject?"

Code at which I am getting this error

Realm realm = Realm.getInstance(this);
List uncaughtExceptions = new ArrayList<>(realm.allObjects(UncaughtException.class));
try {
String json = LoganSquare.serialize(uncaughtExceptions);
Toast.makeText(this, json, Toast.LENGTH_LONG).show();
} catch (IOException e) {
e.printStackTrace();
}

Please do correct me if i am missing something or doing something wrong. New to LoganSquare :)

How to import values from a JSON array when you don't know the keys yet?

Does LoganSquare support importing values from JSON arrays when it's not know what they might be?

For example, for a project I retrieve a JSON that might be filled with certain properties that can change over time as some properties rely on an external source. However, I would like to be able to access/store all of these values.

// Example one, current situation a "query" array has 3 key->value pairs all strings.

"query": {
        "param1": "blablabla",
        "param2": "blablabla",
        "code": "1244"
}

// Example two, new situation, param2 is no longer used, a new key "useKey" with a boolean value has been added.

"query": {
        "param1": "blablabla",
        "code": "1244"
        "useKey": false
}   

I was hoping to do something like this? But I don't know how else I can store a mixed Key->Value array using LoganSquare.
Java:

@JsonObject
public class GameModel {
    @JsonField
    private HashMap<String, Object> query;
}

Any tips on how to solve this problem?

java.lang.Boolean fields should be nullable

The generated JSON parser code uses Boolean.valueOf(jsonParser.getValueAsBoolean()) for java.lang.Boolean fields. However, jsonParser.getValueAsBoolean() defaults to false when the value is null.

ignore fields specifically

Hi, at first congratulations, you've done a great job with the lib, the performance is astonishing.

I was wondering if there is a way to ignore a field specifically for either serializing/parsing, instead of ignoring for both operations.

It is quite common in APIs to have a service that is sent and the server answers with an object of the same type. For instance, a service that updates the profile of a user normally sends a user object with some fields filled and receives as response an updated user. Moreover, sometimes the response can have other fields that we do not want to serialize and although the server check only the needed fields, I find a bad practice to send parameters that wouldn't need to be sent.

Another example could be having a BaseApiResponse super class that acts as a wrapper (contains the response) and other fields like for instance those ones related to error handling. It is something usual that those fields are repeated in most of the services, but those fields shouldn't be sent when sending an instance of the object to the server.

Maybe there is just a way to handle this, I have had a look and I have not found a way to do this, but just in case I am missing something, please excuse me.

I know that a simple way to handle this is to remove chars from the inputstream before sending, but I don't like this approach, I think that this should be done before.

1- I think that a good way to handle this should be using a kind of annotation that lets you exclude a field to be taken into account when serializing or parsing, for instance "@IgnoreSerialization" and "@IgnoreParsing" or just a single one like "@IgnoreSpecifically(op = "serialization").

2- Another way would be to have an annotation like those ones you are using when operations have finished (i.e. "@OnJsonParseComplete") but that is taken into account in the process of the operation. By this way returning a kind of facade have a method ignoreField(field) and this removes unwanted fields.

I would like to know your thoughts, maybe you think that this could affect a little bit the performance and you discard an option like that, but first option would not damage so much performance.

As I told maybe there is just a way to do this, if there is, many apologies.

Thanks a lot

simple custom StringBasedTypeConverter produces "Can not write a field name, expecting a value"

I get this when serializing something with a custom simple typeconverter:

     Caused by: com.fasterxml.jackson.core.JsonGenerationException: Can not write a field name, expecting a value
            at com.fasterxml.jackson.core.JsonGenerator._reportError(JsonGenerator.java:1574)
            at com.fasterxml.jackson.core.json.WriterBasedJsonGenerator.writeFieldName(WriterBasedJsonGenerator.java:102)
            at com.fasterxml.jackson.core.json.JsonGeneratorImpl.writeStringField(JsonGeneratorImpl.java:169)
            at com.bluelinelabs.logansquare.typeconverters.StringBasedTypeConverter.serialize(StringBasedTypeConverter.java:31)
            at no.finn.android.ui.objectpage.ObjectPageContainerScreen$$JsonObjectMapper._serialize(ObjectPageContainerScreen$$JsonObjectMapper.java:70)
            at no.finn.android.ui.objectpage.ObjectPageContainerScreen$$JsonObjectMapper.serialize(ObjectPageContainerScreen$$JsonObjectMapper.java:59)
            at no.finn.android.ui.objectpage.ObjectPageContainerScreen$$JsonObjectMapper.serialize(ObjectPageContainerScreen$$JsonObjectMapper.java:14)

Looking at the code:

    if (object.searchUrl != null) {
      jsonGenerator.writeFieldName("searchUrl");
      FINN_URL_CONVERTER.serialize(object.searchUrl, "searchUrl", jsonGenerator);
    }

This seems wrong, as serialize itself calls jsonGenerator.writeStringField(fieldName, convertToString(object));

Is this can be used in Java Project?

Hello, I want to know the answer about that question : Is this can be used in Java Project? I tried to pack it to .jar and used in a java project, but unfortunaly it failed and i get the exception as Follow:

Exception in thread "main" com.bluelinelabs.logansquare.NoSuchMapperException: Class User could not be mapped to a JSON object. Perhaps it hasn't been annotated with @JsonObject?
    at com.bluelinelabs.logansquare.LoganSquare.mapperFor(LoganSquare.java:171)
    at com.bluelinelabs.logansquare.LoganSquare.serialize(LoganSquare.java:100)
    at JsonTest.main(JsonTest.java:14)
Caused by: java.lang.ClassNotFoundException: User$$JsonObjectMapper
    at java.net.URLClassLoader$1.run(Unknown Source)
    at java.net.URLClassLoader$1.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Unknown Source)
    at com.bluelinelabs.logansquare.LoganSquare.mapperFor(LoganSquare.java:167)
    ... 2 more

Can't it provide in java project? Or i worked in bad way?

Support for exclusive field serialization

The default behaviour now is obviously inclusive - you have to annotate each field with @JsonField. Would it be possible to say that you should serialize every field in this class with for instance an annotation variable? E.g. JsonObject(exclusive=true). Then you could opt out fields instead of opt in, with for instance @JsonIgnore or the transient keyword as native Java serialization does (Naming of annotations does not matter for me)

[Feature Suggestion]: Path expression for fields.

It would be great to be able to annotate a field with an XPath-like expression in addition to just a field name. The use case for this is to have a flatter POJO hierarchy than the JSON.

Example:

{
  "some-meta-data": "foobar",
  "comment": 
    {
      "user": "Me",
      "timestamp": 12345678,
      "text": "WooHoo what an awesome comment"
    }
}

Currently, if I am not interested in the metadata, I am still forced to create a top level Java object.

class Response {

  @JsonField
  Comment comment;

  static class Comment {
    @JsonField String user;
    @JsonField long timestamp;
    @JsonField String text;
  }
}

Using an XPath-like expression, I could maybe even eliminate the need to create the top-level Response class altogether.

@JsonPathRoot("$.comment")
class Comment {
  @JsonField String user;
  @JsonField long timestamp;
  @JsonField String text;
}

Or perhaps, using a XPath expression, that might be @JsonPathRoot("//comment").

Prior art:

IMO these libraries serve a different purpose - querying large JSON data to extract certain information. For POJO-JSON mapping, a far simpler syntax would suffice.

None of the popular JSON mapping libraries for Java support this currently. GSON does provide a way to parse a JsonPath expression, but I did not find a way to specify the Path in place of a field name as an annotation.

Generic classes with type parameters parsing/serializing

Aloha!

For a big project of mine my data is stored as such:

abstract class A <T1, T2> {
    T1 first;
    T2 second;
    ...other simple fields...
}

class B<This,That>{
}

Since the scope for the data is so wide there are N number of classes that all depend on A like this. In GSON I use TypeAdapters to include the class name of each subclass in the json so that it can be read back properly, Id like to see something similar in LoganSquare.

I cannot get it to work the way LoganSquare is built at the moment (If its supported at all?) as it always tries to create instances of A directly.

Thanks!

@JsonObject should be enough, no need to annotate each field with @JsonField

Compared to Jackson, this is the main trouble with LoganSquare.

An annotation processor can be triggered by the @JsonObject annotation but it should then look for all fields, annotated or not and generate code for those fields. We should then add a @JsonIgnore annotation to be able to filter out a few fields.

If we do so, @JsonField can still be used, for instance to give a special name to json entry for a field.

Add handling of collections with polymorphic types

As far as I have seen there is no support for inheritance. I have worked on a very similar project (annotation procession based json parser) with features like you implemented (you have more features though, but the basic features are the same). However, I have implemented Inheritance resolution similar like Jackson did. Since my annotation processor is in alpha and I consider your parser as more advanced, I consider to switch over to your parser and I would like to ask you if you would accept pull requests for inheritance or are you currently working on that? Or does your roadmap specifies inheritance for a much later version like 2.0.0?

If you are interested in we can specify together the annotations.

Re: Not an issue, but a question.

How did you guys get the benchmarks from. Can you please tell the way to get the benchmarks so that, we can demo it to our leads and use LoganSquare in our apps. :)

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.