Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 2 years ago.
Improve this question
I'm deciding on whether to use Moshi by square or Gson to serialize and deserialize model data.
one thing i always did not like about Gson is i think it uses reflection which can be slow on android? Does Moshi use reflection also?
What are some of the pros and cons of moshi vs Gson?
I see them as similar. take for example this statement that creates a typeAdapter:
class CardAdapter {
#ToJson String toJson(Card card) {
return card.rank + card.suit.name().substring(0, 1);
}
#FromJson Card fromJson(String card) {
if (card.length() != 2) throw new JsonDataException("Unknown card: " + card);
char rank = card.charAt(0);
switch (card.charAt(1)) {
case 'C': return new Card(rank, Suit.CLUBS);
case 'D': return new Card(rank, Suit.DIAMONDS);
case 'H': return new Card(rank, Suit.HEARTS);
case 'S': return new Card(rank, Suit.SPADES);
default: throw new JsonDataException("unknown suit: " + card);
}
}
}
and to use it register it just like in gson:
Moshi moshi = new Moshi.Builder()
.add(new CardAdapter())
.build();
I guess the advantages would be the annotation being used in the typeAdapter. I'm looking to find out if there are any performance gains if I switch to Moshi.
Moshi uses Okio to optimize a few things that Gson doesn’t.
When reading field names, Moshi doesn’t have to allocate strings or do hash lookups.
Moshi scans the input as a sequence of UTF-8 bytes, converting to Java chars lazily. For example, it never needs to convert integer literals to chars.
The benefits of these optimizations are particularly pronounced if you’re already using Okio streams. Users of Retrofit and OkHttp in particular benefit from Moshi.
Further discussion on the origins of Moshi are in my post, Moshi, another JSON Processor.
According to swankjesse's comment on reddit:
I’m proud of my work on Gson, but also disappointed by some of its limitations. I wanted to address these, but not as “Gson 3.0”, in part because I no longer work at Google.
Jake, Scott, Eric, and I created Moshi to address the various limitations of Gson. Here’s ten small reasons to prefer Moshi over Gson:
Upcoming Kotlin support.
Qualifiers like #HexColor int permit multiple JSON representations for a single Java type.
The #ToJson and #FromJson make it easy to write and test custom JSON adapters.
JsonAdapter.failOnUnknown() lets you reject unexpected JSON data.
Predictable exceptions. Moshi throws IOException on IO problems and JsonDataException on type mismatches. Gson is all over the place.
JsonReader.selectName() avoids unnecessary UTF-8 decoding and string allocations in the common case.
You’ll ship a smaller APK. Gson is 227 KiB, Moshi+Okio together are 200 KiB.
Moshi won’t leak implementation details of platform types into your encoded JSON. This makes me afraid of Gson: gson.toJson(SimpleTimeZone.getTimeZone("GMT"))
Moshi doesn’t do weird HTML escaping by default. Look at Gson’s default encoding of "12 & 5 = 4" for an example.
No broken Date adapter installed by default.
If you’re writing new code, I highly recommend starting with Moshi. If you’ve got an existing project with Gson, you should upgrade if that’ll be simple and not risky. Otherwise stick with Gson! I’m doing my best to make sure it stays compatible and dependable.
From the previous link you can see that using moshi codegen will create compile time adapters to model classes, which will remove the usage of reflection in runtime
Model
#JsonClass(generateAdapter = true)
class MyModel(val blah: Blah, val blah2: Blah)
app/build.gradle
kapt "com.squareup.moshi:moshi-kotlin-codegen:$version_moshi"
Will generate a MyModelJsonAdapter class with validations to ensure the nullablility of the model properties.
Related
I would like to know what is the best way to integrate Retrofit with MoShi on my Android Studio project.
First of all, I use the moshi converter of retrofit :
implementation 'com.squareup.retrofit2:converter-moshi:2.9.0'
I use the popular plugin "Json to Kotlin class" for the generation of my POJO :
https://plugins.jetbrains.com/plugin/9960-json-to-kotlin-class-jsontokotlinclass-
When I create a new POJO, I use the annotation "MoShi (Reflect)" :
It generate me a Pojo with fields like this one :
#Json(name = "image_url")
val imageUrl: String?
The problem is Retrofit2 seem don't like underscore in my fields name because I get null results with the underscored names.
Searching in the Github issues, I found a solution. It work if I use this annotation :
#field:Json(name = "image_url")
val imageUrl: String?
So my questions are :
Using the #field:Json annotation is the best way to use MoShi with Retrofit ?
If yes, how to generate easily a Kotlin class with this annotation (using the same plugin or an other) ?
As apparent from this part of Moshi's documentation: "There’s no field naming strategy, versioning, instance creators, or long serialization policy. Instead of naming a field visibleCards and using a policy class to convert that to visible_cards, Moshi wants you to just name the field visible_cards as it appears in the JSON."
The preferred way is for you to not use the annotation, but instead name the fields the same way as in the JSON. With Kotlin you can use backticks for names that wouldn't otherwise be valid, e.g.val `image-url`: String?
Of course you wouldn't want to be working with such names in other parts of your code, and for that you should have separate objects for describing the data as it appears on the back-end, and another object for how it should appear in your application. We call those DTOs (Data-Transfer Objects.)
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 2 years ago.
Improve this question
Considering that starting from version 8 Java is much more clear and readable than Kotlin.
At the and Kotlin code get translated into Java anyway and it is very hard to understand what the code is really doing without plenty of comments that explains it, or autocompletition.
For example:
override fun onClick(v: View) {
val amountTv: EditText = view!!.findViewById(R.id.editTextAmount)
val amount = amountTv.text.toString().toInt()
val action = SpecifyAmountFragmentDirections.confirmationAction(amount)
v.findNavController().navigate(action)
}
How do I know what kind of object is the val "action"?
Considering that starting from version 8 Java is much more clear and readable than Kotlin
Its just matter of taste, everybody has his own opinion, similar to your consideration Google team may found Kotlin good option to be more clear and concise.
Why pushing new dev so much on kotlin if it has nothig more than java?
Kotlin is alot different than just plain Java, the docs itself say much about it, here's brief differences:
Null-safety - Kotlin's type system is aimed at eliminating the danger of null references from code, also known as the The Billion Dollar Mistake.
Your app won't even compile until you remove all possibilities of NPE, otherwise you decide to axing your own feet by null-assertion operator (!!)
Coroutines - Light weight implementation of concurrency model, not only limited to multi-threading but also to the extent of doing deep-recursion, shared mutable-state and structured-concurrency, and also provides a lot of standard utilities for faster development like Flows. Being a lightweight implementation it is slightly faster in many situations than its competitors like RxJava.
Immutability - Proper handling of Collections (difference in read-only and mutable).
Similar goes to variables, Kotlin by default instructs you to use val until you required to change it later in order to provide a thread-safety.
Declaration-site Variance - Kotlin allows you to specify generic variances at declaration-site that will save you a lot of time, and hence less bugs.
Proper function types (i.e. lambda) and higher order functions - There's native support for the lambda expressions, and the support for the inline function makes it possible to counter the performance overhead of memory allocations (both for function objects and classes) and virtual calls introduce runtime overhead.
Smart-casts - no need to cast an object when checks have been made.
if (variable is String) {
println(variable.length) // no need to cast to String :P
}
Functional extensions - let, run, also, apply, with, use. These are very useful in concise code and hence boosts productivity.
// Java version
var a = Api.result();
Log.i(Tag, a.toString());
return a;
// Kotlin version
return Api.result().also { Log.i(Tag, it.toString()) }
Default parameters - You can mark a field as optional and just use 1 single function which is easier to manage later on rather than overloading function like 5 times and manage them all when updating a piece of code.
Native support for delegation - Defining getters and setters once and use them for as many field/properties as you want. There are delegates provided by std-lib like lazy (do-not allocate memory in RAM till property is accessed for the first time), observable (observe the changes in variable with both old and new value), etc.
Delegation of classes - You can implement a class using another object, useful when you want to extend some functionality of class but want to let other untouched. For examples see: Delegation of Classes
Inline functions and reified generics - In java it is impossible to use generics inside of a function because of JVM type-erasure. But this is not the case in Kotlin, you can embed the function into the callsite (at the compile time) using inline modifier and access generics via making it reified.
Destructing Declarations - Create multiple variable in same line using a destructing object, see Kotlin: Destructuring Declarations for examples.
Edit:
Forgot to put the answer to the code block, the amount has the same type returned by toInt(), and action has the same type as returned by confirmationAction(amount). Using an IDE will show that to you the inferred types in front of the variable names, you can also jump at the sources through some Ctrl+MouseClick at the call-site.
type of val action is same as the return type of confirmationAction method in SpecifyAmountFragmentDirections class
It's just that you have been using Java for long time and new to kotlin so you finding kotlin hard to understand.It's just matter of time and once you start using it regularly you will find it easier to understand and read.Moreover lines of code usually becomes less in kotlin.
UPDATE based on comments-
Kotlin has some advantages in comparison to java like it is more safe against NullPointerException which all android developers face many times in java and it is less verbose and less code can mean chances of fewer bugs.So new developers are recommended to learn kotlin for android.
I created a simple Web Server which use Hibernate to store entities on a MySQL database. Also, as you can expect, it shares some libraries with the clients in the <...>.shared> package to access various resources. Among them, there are the POJO classes, annotated with both Hibernate and Jackson annotations. This is an example of a POJO class.
#JsonInclude(Include.NON_NULL)
#Entity
#Table(name = "user", uniqueConstraints =
{ #UniqueConstraint(columnNames = "email"),
#UniqueConstraint(columnNames = "nick") })
public class User implements java.io.Serializable, RecognizedServerEntities
{
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "id", unique = true, nullable = false)
private Integer userId;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "threadAuthor",
orphanRemoval = false)
#Cascade({ CascadeType.SAVE_UPDATE })
private Set<Thread> userThreads = new HashSet<Thread>(0);
}
Now, I'm trying to create an android app that simply use these shared classes: the app doesn't need to know anything about Hibernate, Javax.persistence and maybe even Jackson annotations.
However, when I create a new Android project, it requires a lot of libraries.
74K hibernate-commons-annotations-4.0.5.Final.jar
5,1M hibernate-core-4.3.6.Final.jar
38K jackson-annotations-2.4.0.jar
221K jackson-core-2.4.3.jar
1,1M jackson-databind-2.4.3.jar
180K javax.persistence_2.1.0.v201304241213.jar
714K org.restlet.jar
55K shared.jar
Problem is that they greatly magnify the app size and slow down the development process, because I have to enable Multidex support.
So, how can I solve?
I can think of some solutions:
Change the shared classes in some way to not expose the annotations. Is it a viable solution? How can I efficiently do this?
Use ProGuard. I don't know if it's really a solution because I don't know anything about this tool, but for what I've read it could help to delete classes that aren't used at all in the project.
EDIT: I partially worked around the problem extracting only required casses from hibernate-core-4.3.6.Final.jar, which is the greatest libraries. Still looking for most elegant solutions.
If you think of your application as having layers, you are currently using the same classes across the data access and view layers.
Your database isn't interested in the Jackson annotations, and your Android client isn't interested in the Hibernate annotations.
Two different approaches that I have seen for this are:
- have a parallel 'view' layer representation of your objects that has the Jackson annotations which your application will populate by mapping from your Hibernate annotated data access layer
OR
- have your client application not share the classes of the server application. It parses the JSON and maps the structures into your own client specific model.
These approaches are equivalent, but just vary by where the mapping takes place.
I'm currently using GSON to parse my JSON to Objects. I was using the standard way like :
Result response= gson.fromJson(reader, Result.class);
Result can be a very complex object with other Complex objects, with up to 5 levels of complex objects. But I have no issues with that.
My Question is : I would like to be able to have in some objects an attribute with a flexible type.
For example :
class Class1 {
String hello;
}
class Class2 {
String world;
}
class Class3 {
Class<?> (= class1 or class2) hello;
}
// Parsing time
Class<?> response= gson.fromJson(reader, Class3.class);
try {
Class1 ret = (Class1)response;
} catch ... {
Class2 ret = (Class2)response;
}
Hope it's clear enough.
Unfortunately, the latest release of Gson (2.0) still doesn't have built-in support for an easy configuration to provide polymorphic deserialization. So, if Gson must be used (instead of an API that has such built-in support, like Jackson -- using which I've posted complete examples for polymorphic deserialization at http://programmerbruce.blogspot.com/2011/05/deserialize-json-with-jackson-into.html), then custom deserialization processing is necessary.
For deserialization to polymorphic types, something in the JSON must be present to identify which concrete type to deserialize to.
One approach would be to have an element in the JSON dedicated to just this purpose, where the deserialization code selects the correct type based on the value of the special-purpose element. For example:
{"type":"Class1","hello":"Hi!"} --> deserializes to Class1 instance
{"type":"Class2","world":"Earth"} --> deserializes to Class2 instance
Another approach would be to just switch on the presence of particular JSON element names, though instead of try-catch blocks as demonstrated in the original question, I'd just use if-statements.
See Gson issue 231 for more on this topic, as well as possible information on when a built-in polymorphic deserialization facility might be included in Gson.
Another StackOverflow.com post with an example of polymorphic deserialization with Gson is Polymorphism with gson
I have something like the following json string:
{"values" : [
{ "group":"A"
"rating":2
},
{
"group":"B"
"language":"english"
}
]
}
As you can see, "values" is an array, with different type of objects. One type can contain a string and an integer, and the other type contains a string and another string.
How do I deal with this?
Sorry, I didn't notice originally you wrote "gson". I'm not sure you can do it, and here's not me saying it.
Do some thing like the following
List myStrings = new ArrayList();
myStrings = gson.fromJson(json,myStrings.getClass());
Iterator myIterator = myStrings.iterator();
boolean b;
while(myIterator.hasNext()){
Object o =myIterator.next();
b=o instanceof String;
System.out.println("...."+b);
}
My approach would probably be to implement a polymorphic deserialization solution.
Gson does not currently have a simple mechanism for polymorphic deserialization, other than implementing custom deserialization processing. The next release looks like it will provide a built-in solution.
Previous StackOverflow.com Questions And Answers (Some With Examples) On This Topic:
Deserialising a generic with unknown compile time type where a field indicates the type
Parse JSON with no specific structure for a field with GSON
json object serialization/deserialization using google gson
Polymorphism with gson
Specific to the original question, it looks like the "group" element would be used to distinguish between different types.
FWIW, Jackson released a built-in solution to this problem many moons ago.