I am writing some RESTful services using spring MVC. I am using jsckson mapper to do the It conversions.
It all works fine except that the json it produces has fields completely unordered.
for e.g.
If my entity object looks like this:
public class EntityObj
{
private String x;
private String y;
private String z;
}
If I now have a list of EntityObjs, and I return this back from the controller, the json has the order mixed up for the fields e.g.:
[{y:"ABC", z:"XYZ", x:"DEF"},{y:"ABC", z:"XYZ", x:"DEF"}]
Looked around for a solution but not finding any. Anyone else faced this issue?
Thanks for the help
As others suggested, ordering should not matter. Nonetheless, if you prefer certain ordering, use #JsonPropertyOrder annotation like so:
#JsonPropertyOrder({ "x", "y", "x" })
public class EntityObj {
}
If alphabetical order suit you and you are using Spring Boot, you can add this in your application.properties :
spring.jackson.mapper.sort-properties-alphabetically=true
I realized this doesn't work with variable names that start with upper case letters. For example a variable named "ID" will not be ordered.
If you don't want to explicitly define the field order as done in the accepted answer, you can simply use:
#JsonPropertyOrder(alphabetic=true)
Related
When the entity classes were first created they were modeled in JPA to match database field names. For our rest endpoints we used JsonProperty to let Jackson auto map names the client would expect they are kabob case. However we are now implementing search functionality and are building it using QueryDSL. It works and works well as long as we use the internal field names.
What we are looking to do though is accept querystrings with the JsonProperty Name.
Like: campaign-grouping-code=123 vs groupingCode=123
I am assuming it would probably have to be done in the Q Classes that are generated but can't find much documentation on them.
#Column(name = "GROUPING_CODE")
private String groupingCode;
#JsonProperty("campaign-grouping-code")
#NotBlank(message = "1", groups = CampaignFieldCheck.class)
#Size(max = 40, message = "100", groups = CampaignFieldCheck.class)
public String getGroupingCode() {
return groupingCode;
}
public void setGroupingCode(String groupingCode) {
this.groupingCode = groupingCode;
}
Quite simply: no that is not possible because the Spring Data endpoints use the values from the attributes in the metamodel, which in the case for querydsl-jpa are always the JPA attribute names, which are in turn derived from the field names, and - is not a valid character in a Java field name.
So there isnt a way to get the jsonproperty names to work. There is a workaround aliasing.. In this link you can find the black list and white list settings. Aliases are automatically white listed. but the aliases can be mapped via whatever text string makes sense to the field names.
https://gt-tech.bitbucket.io/spring-data-querydsl-value-operators/README.html
I'm trying to read this JSON:
And I can't seem to get it to work with GSON. I've used GSON successfully in the same project so I know how it works but I can't seem to get this JSON to work as intended. First in the class is rows, which is just an array of another class. The other class has three variables, a string named "code", a string named "name", and a array of another class called "statuses". However, I don't know how to put variables in this other class. It looks like an array but it's not. I cannot name a variable "0" in Java, so I looked that up (tried fixing it with Maps) but that did not work. How would you do this? It's weird because "statuses" always contains just that one entry, named '0', and the text is either "primary" or "secondary". Any help is appreciated.
I actually found this:
Still not really sure how to go about this.
Your Pojo design shoild be like this :-
public class ResultOutPut {
private List<Rows> rows;
// getters and setters
}
public class Rows {
private String code;
private String name;
private List<String> statuses;
// getters and setters
}
I'm using Gson library to parse JSON objects. In particular, I've got a JSON like this:
{
"key": ["string1", "string2"]
}
and I would like to parse it in a simple String[], without building a specific object. I tried this way:
gson.fromJson(json, String[].class);
but I had an error: "Expected BEGIN_OBJECT but was BEGIN_ARRAY", I guess because of the presence of the key. Any ideas how should I fix it?
Create a class that has a key property that has type of String[] and deserialize to that.
public class Thing
{
private String[] key;
public String[] getKey() {
return key;
}
}
Thing thing = gson.fromJson(json, Thing.class);
Since tvanfosson answer is perfect, I should not add anything but in the comment you asked is it's possible to avoid creating the Thing class. Yes, it is but I think is more fragile. I'm going to show you how to do with this code:
String json = "{\"key\": [\"string1\", \"string2\"]}";
String mJson = json.replace("{\"key\":", "").replace("}","");
String[] strings = new Gson().fromJson(mJson, String[].class);
System.out.println(Arrays.asList(strings));
Of course this code runs without errors and avoids you additional classes, but think to what happens if there's some carriage return inside. It breaks, unless you user a regexp inside the replace invocation. At this point I prefer to add a class instead of thinking of right regexp and let Gson do the whole work.
I added this as response and not as comment to have enough space to explain myself, but this answer should not be taken as right response but instead as poor hack to use. It pays better to understand a bit more how Gson reasons.
I need to add new property to an object, when serializing to JSON. The value for the property is calculated on runtime and does not exist in the object. Also the same object can be used for creation of different JSON with different set ot fields (kind of having a base class with subclasses, but I don't want to create ones just for JSON generation).
What is the best way of doing that, which doesn't involve creation of custom serializer class, which will take care of serializing of whole set of object's fields? Or may be it is possible to inherit some "basic" serializer, and simply take it's output and add new field to it somehow?
I learned about mixins, and looks like it is possible to rename/hide some fields, however it seems not be possible to add an extra one.
Can you not just add a method in value class? Note that it does not have to be either public, or use getter naming convention; you could do something like:
public class MyStuff {
// ... the usual fields, getters and/or setters
#JsonProperty("sum") // or whatever name you need in JSON
private int calculateSumForJSON() {
return 42; // calculate somehow
}
}
Otherwise you could convert POJO into JSON Tree value:
JsonNode tree = mapper.valueToTree(value);
and then modify it by adding properties etc.
2021 calling...
Simplest way I found to do this is #JsonUnwrapped:
public class Envelope<T> {
#JsonUnwrapped // content's fields are promoted alongside the envelope's
public T content;
// Transmission specific fields
public String url;
public long timestamp;
}
This works (bi-directionally) so long as Envelope's fieldnames do not clash with those of content. Also has a nice feature of keeping the transmission properties at the end of the serialised JSON.
One option is to add a field for this property and set it on the object before writing to JSON. A second option, if the property can be computed from other object properties you could just add a getter for it, for example:
public String getFullName() {
return getFirstName() + " " + getLastName();
}
And even though there's no matching field Jackson will automatically call this getter while writing the JSON and it will appear as fullName in the JSON output. If that won't work a third option is to convert the object to a map and then manipulate it however you need:
ObjectMapper mapper //.....
MyObject o //.....
long specialValue //.....
Map<String, Object> map = mapper.convertValue(o, new TypeReference<Map<String, Object>>() { });
map.put("specialValue", specialValue);
You're question didn't mention unmarshalling but if you need to do that as well then the first option would work fine but the second two would need some tweaking.
And as for writing different fields of the same object it sounds like a job for #JsonView
I have a class that contains a few private/protected fields and some public getters that return the value of the fields. I am attempting to map the fields to database columns using the fluent API on the DbModelBinder in OnModelCreating. I cannot use an automatic property with a protected setter so please don't offer that as a solution to my question. It would probably work I'm sure but I cannot use the automatic property as the domain class is shared code and used with other different ORMs that have different ways of mapping their fields and unfortunately one doesn't support the au
I use the following code (found on stackoverflow) to access the protected field so that I can use the expression when mapping:
public static class ObjectAccessor<T>
where T : class
{
public static Expression<Func<T, TResult>> CreateExpression<TResult>(string propertyOrFieldName)
{
ParameterExpression param = Expression.Parameter(typeof(T), "propertyOrFieldContainer");
Expression body = Expression.PropertyOrField(param, propertyOrFieldName);
LambdaExpression lambda = Expression.Lambda(typeof(Func<T, TResult>), body, param);
return (Expression<Func<T, TResult>>)lambda;
}
}
This all works wonderfully if the field name is m_username but if I use _username I get a ModelValidationException: One or more validation errors were detected during model generation: System.Data.Edm.EdmProperty: Name: The specified name is not allowed: '_username'.
I can't use camelcase without the underscore either as the helper above can't distinguish between the public Username property and the protected username field. I'd really like to still keep using the underscore camelcase without the letter prefix.
Is it possible to configure the ModelBinder in some way so that the validation accepts the property name with a leading underscore?
Thanks in advance,
Mark
It seems that decoration of your field like this :
[Column("username")]
public string _username
maybe helpful in your case, anyway - please review similar case