Giter Site home page Giter Site logo

lachlanmckee / gsonpath Goto Github PK

View Code? Open in Web Editor NEW
59.0 7.0 3.0 1.38 MB

A Java annotation processor library which generates gson type adapters using basic JsonPath style annotations

License: MIT License

Java 42.05% Kotlin 57.95%
annotations json gson java-annotation-processor java kotlin android annotation-processor annotation-processor-library jsonpath

gsonpath's People

Contributors

lachlanmckee 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

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

gsonpath's Issues

Add support for Kotlin data classes

Currently Gsonpath will not work with Kotlin data classes as the fields are marked as private, and the library does not currently use constructors.

The proposed change is to make the library use the data classes constructor to correctly instantiate the data class.

Due to the way in which Kotlin classes are accessed via the annotation processor, there is no way to distinguish the difference between a Kotlin data class, and a regular java class. Therefore the library must be updated in such a way that all POJOs can be instantiated via their constructor.

Create a json array auto type adapter

Currently the @AutoGsonAdapter creates an automatic TypeAdapter object which removes a lot of complexity around deserializing a Json object into a Java POJO.

However when attempting to read a Json Array (either nested within a Json Object, or a Json Array which exists at the root) a developer would still need to write a custom TypeAdapter to read this.

For example, when nested in an object the TypeAdapter would be similar to:

List<PersonModel> result = null;
jsonReader.beginObject();

while (jsonReader.hasNext()) {
    switch (jsonReader.nextName()) {
        case "people":
            result = gson.fromJson(jsonReader, new TypeToken<List<PersonModel>>() {}.getType());

        default:
            jsonReader.skipValue();
    }
}
jsonReader.endObject();

return result;

Another consideration relates to streaming the Json array. It can be extremely advantageous to stream the array either one record at a time, or in chunks. This has the benefit of:

  • reducing the amount of classes in memory
  • allows the developer to execute actions based on the portion of content they have at any given time.
  • potentially allows the developer to cancel reading the Json array early, thus preventing pointless parsing.

The requirement is to create another annotation which will generate a class which provides the above features.

Add full json reader consumption to Array Streamer

At the moment the Array Streamer functionality exits from the json reader as soon as it finds the result it looking for.

Unfortunately this will cause the json reader to be in an unknown state where it has not finished reading the entire json tree correctly.

There are some benefits to not reading the json tree, but by default it should read the entire tree to ensure that compatibility is maintained with other Gson functionality.

An annotation field should be exposed which allows a developer to disable reading the entire tree. This would normally be done where the array is the only element being consumed and the reader can be discarded immediately.

Add 'toString' code generation to annotated interfaces

Similar to the way in which the equals and hashcode methods are being generated by interfaces annotated with the AutoGsonAdapter annotation, the toString method would also be very useful to generate.

For now the IntelliJ Idea autogenerated toString code style will be used. e.g.:

  @Override
  public String toString() {
    return "InterfaceExample{" +
            "intExample=" + intExample +
            ", longExample=" + longExample +
            ", doubleExample=" + doubleExample +
            ", booleanExample=" + booleanExample +
            ", intArrayExample=" + Arrays.toString(intArrayExample) +
            ", longArrayExample=" + Arrays.toString(longArrayExample) +
            ", doubleArrayExample=" + Arrays.toString(doubleArrayExample) +
            ", booleanArrayExample=" + Arrays.toString(booleanArrayExample) +
            ", booleanArrayExampleTest=" + booleanArrayExampleTest +
            '}';
  }

Interface generated *_GsonPathModel class name collision

The generated *_GsonPathModel classes use two variables for the hashCode and equals methods. These variables have extremely common names (result and that) and it is reasonably possible for name collisions.

These names should be changed to something that will be less likely to collide.

The new variables should be equalsOtherType and hashCodeReturnValue. While these will still cause collisions, it is extremely unlikely that a user would have a field with the same name.

Interface support generic

hi @LachlanMcKee
I write a generic interface, but the code gen error

@AutoGsonAdapter
public interface ApiResponse<T> {
  List<T> result();
}
public final class ApiResponse_GsonPathModel implements ApiResponse {
  private final List<T> result;
  ...
}

Add polymorphism support to the generated code

There is an example of polymorphism in the gsonpath-sample sub-module which demonstrates the usefulness of having polymorphism support via gson.

The benefit is that a json response that contains an array of elements that are not homogeneous to be deserialized into different classes.

The new feature would be to expose the ability to add polymorphism support to the library in such a way that the TypeAdapter factory used to facilitate the polymorphism can be localized to a specific class, meaning different of polymorphism can be used in different classes without being restrictive.

The proposed API changes would introduce a new annotation called GsonSubtype which can be used to annotate fields or methods (in the case of interfaces).

It would allow developers specify the field within the json object that specifies the type, and then delegate a class depending on the value. It should be possible to add type conditions based on Strings, Integers and Booleans.

E.g.

@GsonSubtype(
    fieldName = "type",
    failOnMissingKey = true, // This would throw an exception if an unexpected type appeared.
    stringKeys = {
        @GsonSubtype.StringKey(key = "type1", subtype = Type1.class),
        @GsonSubtype.StringKey(key = "type2", subtype = Type2.class),
        @GsonSubtype.StringKey(key = "type3", subtype = Type3.class)
    }
)
@GsonSubtype(
    fieldName = "type",
    failOnMissingKey = true, // This would throw an exception if an unexpected type appeared.
    integerKeys = {
        @GsonSubtype.IntegerKey(key = 0, subtype = Type1.class),
        @GsonSubtype.IntegerKey(key = 1, subtype = Type2.class),
        @GsonSubtype.IntegerKey(key = 2, subtype = Type3.class)
    }
)
@GsonSubtype(
    fieldName = "type",
    failOnMissingKey = true, // This would throw an exception if an unexpected type appeared.
    booleanKeys = {
        @GsonSubtype.BooleanKey(key = true, subtype = Type1.class),
        @GsonSubtype.BooleanKey(key = false, subtype = Type2.class)
    }
)

Interfaces annotated with AutoGsonAdapter fails to generate depending on field order

The generated type adapter and the generated POJO for an interface annotated with @AutoGsonAdapter order their fields differently in scenarios where Json Path notation is used, and the fields using the same parent path are not grouped together. This causes the constructor call inside the type adapter to receive the incorrect ordering of parameters.

The expected behaviour is that the interface generated pojo is instantiated with fields in the correct order.

Add Java '@Generated' annotation to generated classes

It would be useful to add the @javax.annotation.Generated annotation to all generated code.

The benefits of this is that the classes will easier to exclude from automatic code analysis tools, and inform users to avoid modifying the class.

Add 'equals' and 'hashCode' generation to AutoGsonAdapter interfaces

The POJOs generated interfaces annotated with AutoGsonAdapter cannot be compared with each other since the equals and hashCode methods cannot be added since an implementation cannot be added to the interface.

The proposed feature is to add equals and hashCode method generation to the annotation processor for interfaces.

Gson path defaults

At the moment there are quite a few properties that you can configure on a AutoGsonAdapter annotation.

The current defaults seem fairly reasonable for most cases, however people will always have different requirements and the defaults may be wrong.

As a consequence, a user would have to constantly copy and paste their desired defaults to each individual AutoGsonAdapter annotation.

The proposed solution is to create a GsonPathDefaults annotation which a user could specify their desired defaults in a single location which they can then use as a single source of truth.

The benefits of this is that there would be less code to write, and all the defaults would exist in a central location.

Publish artifacts to Maven Central

It would be great to have the artifacts in maven central in addition to just jitpack. This will guarantee that the artifacts will be available forever.

Add a @Required or @Nonnull annotation

It would be beneficial to create or reuse an annotation to add some validation to the json parsing.

If there is a field which cannot be null it should be the responsibility of the type adapter to throw an exception rather than returning null results

Allow custom management of equals() and hashCode()

This is merely an enhancement proposal, but it would be nice to have.
Sometimes, you would need to de/serialize (and cache) data models coming from a server, which are uniquely identified by their ID. In this case, you want to make sure equals() and hashCode() are consistent with this business logic, so that models having the same ID are equals in the client code as well.
As far as I've seen this is not possible with Gson Path, and it's not very well supported even in Google AutoValue. Is it theoretically possible to allow this, perhaps subclassing an abstract class with the @AutoGsonAdapter annotation, where equals() and hashCode() (and potentially other methods or transient fields) are implemented?

Replace GsonArrayStreamer with list and collection interfaces

The GsonArrayStreamer has a substantially different API than the AutoGsonAdapter annotation API. The complexity of keeping this particular part of the library is non-trivial.

Therefore this part of the library will be replaced with a much simpler implementation. Instead of using a different annotation, the AutoGsonAdapter annotation will now be the only annotation used.

To provide similar functionality, a new feature will be added where annotated interfaces can extend List and Collection. This will allow developers to directly access an array within JSON without creating an unneeded container object.

e.g.

@AutoGsonAdapter
public class PeopleContainer {
    People[] people;

    @AutoGsonAdapter
    public static class People {}
}

Could be replaced with:

@AutoGsonAdapter
public interface PeopleList extends List<PeopleList.People> {
    @AutoGsonAdapter
    public interface People {}
}

or

@AutoGsonAdapter
public interface PeopleList extends Collection<PeopleList.People> {
    @AutoGsonAdapter
    public interface People {}
}

This will be broken into two tasks:

  • Remove the GsonArrayStreamer annotation and annotation processor
  • Added the ability to extend List and Collection for annotated interfaces

Improve generation error messaging

Currently there is some degree of information in the gradle console which informs a user what the annotation processor is doing.

There is not sufficient information when something goes wrong. Most times the processor actually throws an annotation processor error which does not help the user solve the problem.

The requirement is that error messages are handled better.

Interfaces using AutoGsonAdapter require more constraints

The current implementation is not adding annotation processor constraints to the interfaces which will cause the processor to fail without informing the user as to why.

Since the methods within the interface act as getters, the processor must ensure that methods always specify a return type, and cannot have any parameters.

Gson SerializedName alternate support

Add support for the 'alternate' property on the Gson SerializedName annotation.
At the moment this annotation property will be ignored when generating a static type adapter.

The library should respect the property and generate code which honors it.

Add support for Gson FieldNamingPolicy

Currently the existing Gson functionality which provides an easy mechanism to translate java variable names into special json formats does not work. This is due to the nature of precompiled code not knowing what the gson builder is requesting.

The solution will be to add the 'FieldNamingPolicy' enum to the 'AutoGsonAdapter' annotation.

This feature can convert the following name (in java) 'firstName' into (in json) 'first_name'

Generated Type Adapter primitives do not handle nulls

The generated type adapters do not handle null elements for primitives as gracefully as their wrapper class counter parts.

To resolve this issue, the primitives should behave the same way as their wrapper classes, and simply unbox the value if it is not null.

Remove interface extending list/collection support

The existing feature that allows a user create an interface that extends list or collection has become too difficult to maintain within the codebase.

Considering the feature is not that useful, and the cost of maintaining the code is too difficult, it makes sense to remove the feature.

Interface write support

As of issue #111, it is much easier to instantiate the _GsonModel generated class for @AutoGsonAdapter annotated interfaces.

Therefore it makes sense to add TypeAdapter JSON 'write' support.

Path text substitution support

The json path support provided by the library is very useful for accessing nested values with json without having to create separate classes.

It would be very useful to expose a mechanism which allows text substitution within the 'path' notation which could allow a developer to reuse a model and make substitutions from an extending class.

For example, given the following class:

public class SubstitutionBase {
    @SerializedName("{SUB_1}.")
    public int value;
}

A class could extend this and replace the {SUB_1} string similar to the example below:

@AutoGsonAdapter(substitutions = {
        @PathSubstitution(original = "SUB_1", replacement = "example")
})
public class SubstitutionImpl extends SubstitutionBase {
}

Extension support

There are many potentially useful annotation constraints that could be added to Gsonpath.

Unfortunately adding these to the main project would add unwanted dependencies and make the project become difficult to maintain.

To that end, extension support would be extremely useful as other projects could be built that handle validation that does not belong in the core project.

An example of this would be adding support for the Android Support Library annotations. This library is Android specific and adding support would prevent this Gsonpath from being pure Java.

The expected outcome of this enhancement is to add the ability for the main Gsonpath annotation processor to import external extensions and allow the extension to inject code into the generated TypeAdapter code

Android Support

This library looks really handy! Thanks for writing it. It would be great if it was usable with Android. Right now if I add this to my build.gradle:

compile('net.lachlanmckee:gsonpath:1.6.2')

I get this error:

Dex: Error converting bytecode to dex:
Cause: Dex cannot parse version 52 byte code.
This is caused by library dependencies that have been compiled using Java 8 or above.
If you are using the 'java' gradle plugin in a library submodule add
targetCompatibility = '1.7'
sourceCompatibility = '1.7'
to that submodule's build.gradle file.

So it either needs to be compiled with JDK 7 instead of 8, or the source target feature used to generate a compatible JAR file...

Allow @AutoGsonAdapter to be used with interfaces

It would be very useful to allow the @AutoGsonAdapter annotation to be used with an interface.

This would allow the generated code to create an immutable POJO behind the scenes and allow the developer to not worry about how the class is constructed.

This has a very similar behaviour to AutoValue. The main reason for not using AutoValue is due to complexity and a currently unwanted extra dependency.

A benefit of doing this within the library is a guaranteed ordering of the constructor within the generated class, which would ensure that the class would never be initialised incorrectly.

For example, a developer could create the following interface

@AutoGsonAdapter
public interface InterfaceExample {
    Integer getExample();
}

Which would then generate the following POJO:

public final class InterfaceExample_GsonPathModel implements InterfaceExample {
    private final Integer example;

    public InterfaceExample_GsonPathModel(Integer example) {
        this.example = example;
    }

    @Override
    public Integer getExample() {
        return example;
    }
}

A developer may choose to use an interface over a class to ensure that the structure is only ever used for a direct mapping between a json response and a java class. The restrictiveness of the interface could prevent misuse.

Change Field Policy to use NonNull and Nullable annotations

The recent field policy change added two new annotations called "Mandatory" and "Optional"

These were created since it does not make sense to annotate primitives with Nullable and NonNull, as they can never be null.

The introduction of these annotations has meant that developers would need to use another annotation on top of the fairly standard 'NonNull' and 'Nullable' annotations.

The proposed solution is to remove the Mandatory and Optional annotations and use the standard annotations.

The Field Policy should be renamed to be a Field Validation Type which has three states: 'Dont validate', 'Validate all NonNulls' and 'validate everything except nullables'

With the new changes, using the latter two validation types will now cause primitives to always be validated, since they are technically NonNull by design. If a developer does not want to validate a particular primitive, they can simply use the boxed version to avoid the issue.

GsonSubType doesn't handle null subtype fields

At the moment the GsonSubType field does not correctly check if the subtype field is null before attempting to access the value. This causes the following exception to fire:

java.lang.UnsupportedOperationException: JsonNull

	at com.google.gson.JsonElement.getAsString(JsonElement.java:191)

A safeguard should be added to check if the object within the subtype field is JsonNull. if it is, it should be treated the same way as if the field didn't exist at all.

Add support for alternative flattening delimiters

Currently Gson Path only works when using a '.' character to separate each nested json object.

This unfortunately means Gson Path will not work for Json keys which actually have a '.' character within the key.

The proposed solution is to expose a annotation property which lets users override the character if they wish, however it will still default to using the '.' character.

Support for arrays

It would be great if we could select a specific item in an array. (Say you always get an item wrapped in an array, being able to extract from that (useless) wrapper array).

@SerializedName("items[0].episodeNumber")
int episodeNumber;

Let me know what you think.

Add support for more primitive types

Gson supports many more primitive types than are currently supported in gsonpath.

This is done by simply allowing the types to be used, and casting doubles/ints/etc.

The following primitives support should be added:

  • float
  • byte
  • short
  • char

Interface generated equals method is incorrect

The equals method that is generated by annotated interfaces produces code that does not work correctly. i.e. deserializing the same JSON twice would produce two POJOs that when tested for equality, fail.

The expected behaviour is that these two POJOs should be equal.

Migrate annotation processor to Kotlin

Kotlin supports Java 6 bytecode and is a much more expressive and type safe language which should help improve development time and reduce errors.

Migrating the compiler to Kotlin will not have any affect for existing users.

Mandatory fields bugfix - Check default value

Currently the mandatory field code does not check to see whether the POJO has a default value.

In this scenario, the TypeAdapter is incorrectly throwing a JsonFieldMissingException. The POJO field's default value should be used as a fallback when the value is missing in the JSON object.

Fix interface - Java 8 compatibility

Currently the @AutoGsonAdapter annotated interfaces do not allow Java 8 features such as static and default methods.

The consequences of this is that if a developer adds either of these two types of methods, the annotation processor will fail.

The expected behaviour is that the annotation processor will ignore the static and default methods, and handle the interface the same way it handles a pre-Java 8 interface.

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.