I have a document with _id as a parameter. I have the below JSON
{
"_id":{
"$oid":"52af48b5d55148fa0c199643"
},
"email":"example.ex#example.com"
}
Corresponding Java class:
#Document(indexName = "Test")
public class Test {
#Id
#ObjectId
private String _id;
private String email;
}
The conversion of json object is successful but there is a problem in saving the data to elastic search.
org.elasticsearch.index.mapper.MapperParsingException: Field [_id] is a metadata field and cannot be added inside a document. Use the index API request parameters
I have seen some references and came to a conclusion that i cannot use _id.. But am looking for a way to use a JsonProperty but it also does not work as i guess ObjectId uses JsonProperty internally.
Kindly provide suggestions
Just use as following
{
"_id":"52af48b5d55148fa0c199643",
"email":"example.ex#example.com"
}
And remove #ObjectId
Like the error message say, you can't use field with name _id inside the document.
To fix that use "replace all"(or function like that that replace substring in other substring) function, and replace all "_id" occurrence with "id"
Related
For example, I have an entity with the following attribute:
#Entity
public class MyObj {
public String nameOrId;
}
I then proceed to create the repository
public interface MyObjRepository extends JpaRepository<MyObj, String> {
MyObj findByNameOrId(String nameOrId);
}
This fails, because it seems that Spring tokenizes the method name as findBy Name Or Id, instead of findBy nameOrId.
The resulting error is "name" property not found (or similar).
Is there a way to escape the special words ("Or", "And", etc) in the method syntax? Renaming the column to not include those words is not an option.
A workaround is to rename the Java field to avoid special words, while preserving the column name using the #Column annotation.
#Column(name = "nameOrId")
public String nameId;
The JPA method is renamed accordingly.
MyObj findByNameId(String nameOrId);
I have a large nested object. I want to serialise this object in the JSON string, however I need only certain fields to be included. Problem here is that fields could change very frequently and I want to build it in a way that could help me easy include or exclude fields for serialisation.
I know that I can write a lot of code to extract certain fields and build JSON "manually". But I wonder if there are any other elegant way to achieve similar outcome but specifying a list of required fields?
For example having following object structure I want include only id and name in the response:
class Building {
private List<Flat> flats;
}
class Flat {
private Integer id;
private Person owner;
}
class Person {
private String name;
private String surname;
}
Json:
{
"flats" : [
{
"flat":
{
"id" : "1",
"person" : {
"name" : "John"
}
}
}
]
}
You can use gson for serializing/deserializing JSON.
Then you can include the #Expose annotation to use only the fields you require.
Be sure to also configure your Gson object to only serialize "exposed" fields.
Gson gson = GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
Alternative:
You can actually do it the inverse way, marking fields which will not be exposed. You can do this with the transient keyword.
So whatever you want to ignore just add transient to it. Here's how it works on gson.
PS: This works on most Java JSON serializers too.
Using com.fasterxml.jackson.annotation.JsonIgnore is another way to achieve this.
import com.fasterxml.jackson.annotation.JsonIgnore;
class Person {
private String name;
#JsonIgnore
private String surname;
}
It will ignore the surname when the parser converts the bean to json.
Similar annotation will be available in other json processing libraries.
If using Gson, study how to use ExclusionStrategy & JsonSerializer.
Using those is a more flexible way to control serialization since it allows to decide per serialization what to serialize.
Using annotations requires later to add / remove those annotations from fields if there is a need to change what to serialize.
In the case of your example the latter might be more appropriate.
This question might be good startpoint
serialize-java-object-with-gson
I want to map my firebase data object to my pojo. However, my firebase object property name is snake case,
such as; "user_name".
I want to use camelCase on my pojo,
such as; "userName"
I found beautiful answers like this one, however, I couldn't find any sample about snake_case to camelCase mapping.
My pojo;
#SerializedName("content")
private String content;
#SerializedName("user_name")
private String userName;
I'm using the following line of code for mapping. 'content' matches with no problem(with or without #SerializedName annotation) but userName stays as null.
Story story = storySnapshot.getValue(Story.class);
That is also an issue for obfuscation. Is there an elegant way to match the data to pojo?
The problem was #SerializedName annotation. Firebase has its own annotation, which is #PropertyName.
It is important to be careful about getter name because annotation cares about its name too.
The property must be public too.
There is a perfect answer about that on this link.
Final state of my pojo;
#PropertyName("content")
public String content;
#PropertyName("user_name")
public String userName;
What is the basic purpose of #SerializedName annotation in Android using Gson?
Give me some different examples. I can't understand the main purpose of using it.
Java class example,
public class Person {
#SerializedName("name")
private String personName;
#SerializedName("bd")
private String birthDate;
}
This class has two fields that represent the person name and birth date of a person. These fields are annotated with the #SerializedName annotation. The parameter (value) of this annotation is the name to be used when serialising and deserialising objects. For example, the Java field personName is represented as name in JSON.
JSON Example,
{
"name":"chintan",
"bd":"01-01-1990"
}
There are already few answers here,but I would like to add that if you are using ProGuard to Obfuscate your code & don't use #SerializedName("name") in your model class, then your GSON won't work. Because due to obfuscation, your variable names might have changed from String name to String a resulting into broken GSON parsing as GSON will look for key a into json & it will fail.
By specifying #SerializedName, GSON will not look in json based on variable name & will just use specified #SerializedName.
Of Course you can tell proguard to not obfuscate your model, but if you would like to have model obfuscated, then you must specify #SerializedName
Using #SerializedName you are actually telling the Parser when receiving a callback from the server i.e. of a Json format:
{
"name":"John Doe",
}
that when Serializing or Deserializing an object to instead of searching for a key named: "userName", in the Json response, to search for "name".
#SerializedName("name")
var userName: String,
This is good because you may have a model that you would like it to have its members being called with whatever you like.
You can instruct Proguard to not obfuscate your data classes by specifying #Keep on top of the class. This will neither remove nor obfuscate your class. No need to add #SerializedName to each and every field explicitly if the field name is similar to the Json key being used for it.
Let's say in a real-world scenario, your backend dev is giving you this response for an API request you make
{
"name":"John Doe",
"id":"1478"
}
Now, in the data class you make to handle this, there might be chances you want to specify a different variable name at Android side for the fields "name" and "id" that you are getting from backend.
#SerializedName comes to rescue here.
You just need to specify the actual key value you will be getting from backend in the #SerializedName (which will be used to serialize and deserialize) and then you can use a variable name of your choice that stores that value received from the operation.
For example, for the JSON I mentioned earlier, here is how its data class will look like:
data class User(
#SerializedName("name") val userName: String,
#SerializedName("id") val userId: Int
)
Here name, id is used in #SerializedName because it's the backend key.
But I have used userName, userId to store those values.
What is the basic purpose of #SerializedName annotation in Android using Gson?
Give me some different examples. I can't understand the main purpose of using it.
Java class example,
public class Person {
#SerializedName("name")
private String personName;
#SerializedName("bd")
private String birthDate;
}
This class has two fields that represent the person name and birth date of a person. These fields are annotated with the #SerializedName annotation. The parameter (value) of this annotation is the name to be used when serialising and deserialising objects. For example, the Java field personName is represented as name in JSON.
JSON Example,
{
"name":"chintan",
"bd":"01-01-1990"
}
There are already few answers here,but I would like to add that if you are using ProGuard to Obfuscate your code & don't use #SerializedName("name") in your model class, then your GSON won't work. Because due to obfuscation, your variable names might have changed from String name to String a resulting into broken GSON parsing as GSON will look for key a into json & it will fail.
By specifying #SerializedName, GSON will not look in json based on variable name & will just use specified #SerializedName.
Of Course you can tell proguard to not obfuscate your model, but if you would like to have model obfuscated, then you must specify #SerializedName
Using #SerializedName you are actually telling the Parser when receiving a callback from the server i.e. of a Json format:
{
"name":"John Doe",
}
that when Serializing or Deserializing an object to instead of searching for a key named: "userName", in the Json response, to search for "name".
#SerializedName("name")
var userName: String,
This is good because you may have a model that you would like it to have its members being called with whatever you like.
You can instruct Proguard to not obfuscate your data classes by specifying #Keep on top of the class. This will neither remove nor obfuscate your class. No need to add #SerializedName to each and every field explicitly if the field name is similar to the Json key being used for it.
Let's say in a real-world scenario, your backend dev is giving you this response for an API request you make
{
"name":"John Doe",
"id":"1478"
}
Now, in the data class you make to handle this, there might be chances you want to specify a different variable name at Android side for the fields "name" and "id" that you are getting from backend.
#SerializedName comes to rescue here.
You just need to specify the actual key value you will be getting from backend in the #SerializedName (which will be used to serialize and deserialize) and then you can use a variable name of your choice that stores that value received from the operation.
For example, for the JSON I mentioned earlier, here is how its data class will look like:
data class User(
#SerializedName("name") val userName: String,
#SerializedName("id") val userId: Int
)
Here name, id is used in #SerializedName because it's the backend key.
But I have used userName, userId to store those values.