Can you tell me how can I use Gson to extract two distinct object defined in this string:
http://json.parser.online.fr/
I attempt to use
gson.fromJson(json, SeedAttribs.class);
and
gson.fromJson(json, SettingsAttribs.class);
but neither is working. I'm surprised why not.
I would also need a way to replace this json string when particular object eg. SeedAttribs changes. I need a way to rewrite it while SettingsAttribs will NOT change at all.
How can this be done?
Thank you for answers!
Make sure your original JSon string contains correct format. The best way is to serialize your object with GSON. Here is the code:
public static void main(String[] args)
{
Gson gson = new Gson();
SettingsAttribs st = new SettingsAttribs();
st.setField1("value1");
st.setField2("value2");
// report constructed object
System.out.println("st: " + st);
// serialize to json
String json = gson.toJson(st, SettingsAttribs.class);
System.out.println("json: " + json);
// deserialize form json
SettingsAttribs restoredSettings = gson.fromJson(json, SettingsAttribs.class);
System.out.println("restoredSettings: " + restoredSettings);
}
It compiles and runs. The output it produces:
st: SettingsAttribs [field1=value1, field2=value2]
json: {"field1":"value1","field2":"value2"}
restoredSettings: SettingsAttribs [field1=value1, field2=value2]
And SettingsAttribs class:
public class SettingsAttribs
{
private String field1;
private String field2;
public String getField1()
{
return field1;
}
public void setField1(String field1)
{
this.field1 = field1;
}
public String getField2()
{
return field2;
}
public void setField2(String field2)
{
this.field2 = field2;
}
#Override
public String toString()
{
return "SettingsAttribs [field1=" + field1 + ", field2=" + field2 + "]";
}
}
Related
Using the Jackson Hash Mapper with Flatten=true my Date fields are getting discarded. Is this the correct behaviour or a bug? Is there a way to have Date serialized with Flatten=true?
I've used the following test Pojo:
import java.util.Date;
public class FooClass{
private Boolean foolean;
private Integer barteger;
private String simpleString;
private Date myDate;
public void setFoolean(Boolean value){ foolean = value; }
public Boolean getFoolean(){ return foolean; }
public void setBarteger(Integer value){ barteger = value; }
public Integer getBarteger(){ return barteger; }
public void setSimpleString(String value) { simpleString = value; }
public String getSimpleString(){ return simpleString; }
public void setMyDate(Date value) { myDate = value; }
public Date getMyDate(){ return myDate; }
}
public class Main {
public static void main(String[] args) throws ParseException,
JsonParseException, JsonMappingException, IOException {
Jackson2HashMapper hashMapper = new Jackson2HashMapper(true);
FooClass fooObject = new FooClass();
fooObject.setFoolean(true);
fooObject.setBarteger(10);
fooObject.setSimpleString("Foobar");
fooObject.setMyDate(new Date());
Map<String, Object> hash = hashMapper.toHash(fooObject);
for (String key: hash.keySet())
{
System.out.println("hash contains: " + key + "=" +
hash.get(key.toString()));
}
FooClass newFoo = (FooClass)(hashMapper.fromHash(hash));
System.out.println("FromHash: " + newFoo);
}
}
In this case I get the following output:
hash contains: #class=FooClass
hash contains: foolean=true
hash contains: barteger=10
hash contains: simpleString=Foobar
FromHash: FooClass#117159c0
If I change new Jackson2HashMapper(false); then I get:
hash contains: #class=FooClass
hash contains: foolean=true
hash contains: barteger=10
hash contains: simpleString=Foobar
hash contains: myDate=[java.util.Date, 1547033077869]
FromHash: FooClass#7ed7259e
I was expecting to get the Date field serialized in both cases - perhaps with an additional field describing the date type (flattened).
I traced the reason for this to the following line in the HashMapper code:
typingMapper.enableDefaultTyping(DefaultTyping.NON_FINAL, As.PROPERTY);
Where the mapper is configured.
It seems to issue in Jackson2HashMapper.
After digging into the source of Jackson2HashMapper, it seems to issue in Jackson2HashMapper.
created an issue for this, DATAREDIS-1001
Jackson2HashMapper does not serialize Date/Calender fields when flatten = true
I am trying to read a json message from kafka and got an exception, which says Jackson cannot deserialize the json to POJO.
The json is like {"code":"500","count":22,"from":1528343820000,"to":1528343880000}, which is an output of kafka stream.
The POJO declares all attributes of the json, and is exactly the same POJO to produce the json message. So I have no idea why it would happen.
I am using spring cloud stream 2.0.0.RELEASE.
Any help would be appreciated. Thanks.
POJO:
public class CodeCount {
private String code;
private long count;
private Date from;
private Date to;
#Override
public String toString() {
return "CodeCount [code=" + code + ", count=" + count + ", from=" + from + ", to=" + to + "]";
}
public CodeCount(String code, long count, Date from, Date to) {
super();
this.code = code;
this.count = count;
this.from = from;
this.to = to;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public long getCount() {
return count;
}
public void setCount(long count) {
this.count = count;
}
public Date getFrom() {
return from;
}
public void setFrom(Date from) {
this.from = from;
}
public Date getTo() {
return to;
}
public void setTo(Date to) {
this.to = to;
}
}
Stacktrace:
2018-06-07 15:18:51.572 ERROR 1 --- [container-0-C-1] o.s.integration.handler.LoggingHandler : org.springframework.messaging.converter.MessageConversionException: Could not read JSON: Cannot construct instance of `com.example.CodeCount` (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
at [Source: (byte[])"{"code":"500","count":22,"from":1528343820000,"to":1528343880000}"; line: 1, column: 2]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `com.example.CodeCount` (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:67) ~[jackson-databind-2.9.3.jar!/:2.9.3]
at com.fasterxml.jackson.databind.DeserializationContext.reportBadDefinition(DeserializationContext.java:1451) ~[jackson-databind-2.9.3.jar!/:2.9.3]
at com.fasterxml.jackson.databind.DeserializationContext.handleMissingInstantiator(DeserializationContext.java:1027) ~[jackson-databind-2.9.3.jar!/:2.9.3]
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1275) ~[jackson-databind-2.9.3.jar!/:2.9.3]
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:325) ~[jackson-databind-2.9.3.jar!/:2.9.3]
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:159) ~[jackson-databind-2.9.3.jar!/:2.9.3]
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4001) ~[jackson-databind-2.9.3.jar!/:2.9.3]
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3109) ~[jackson-databind-2.9.3.jar!/:2.9.3]
at org.springframework.messaging.converter.MappingJackson2MessageConverter.convertFromInternal(MappingJackson2MessageConverter.java:221) ~[spring-messaging-5.0.6.RELEASE.jar!/:5.0.6.RELEASE]
... 37 common frames omitted
Jackson needs access to the default constructor to deserialize, add the default constructor to the pojo, ie:
public CodeCount() {
}
You can annotate the existing constructor, and args, and Jackson will use this:
#JsonCreator
public CodeCount(#JsonProperty("code") String code,
#JsonProperty("count") long count,
#JsonProperty("from") Date from,
#JsonProperty("to") Date to) {
super();
this.code = code;
this.count = count;
this.from = from;
this.to = to;
}
Passing in the dates may complicate it a bit, but it is definitely still possible.
i have two Presenters: A DevicePresenter and a ContainerPresenter. I place a PlaceRequest in the DevicePresenter to call the ContainerPresenter with some parameters like this:
PlaceRequest request = new PlaceRequest.Builder()
.nameToken("containersPage")
.with("action","editContainer")
.with("containerEditId", selectedContainerDto.getUuid().toString())
.build();
placeManager.revealPlace(request);
In my ContainersPresenter i have this overridden method:
#Override
public void prepareFromRequest(PlaceRequest placeRequest) {
Log.debug("prepareFromRequest in ContainersPresenter");
super.prepareFromRequest(placeRequest);
String actionString = placeRequest.getParameter("action", "");
String id;
//TODO: Should we change that to really retrieve the object from the server? Or should we introduce a model that keeps all values and inject that into all presenters?
if (actionString.equals("editContainer")) {
try {
id = placeRequest.getParameter("id", null);
for(ContainerDto cont : containerList) {
Log.debug("Compare " + id + " with " + cont.getUuid());
if(id.equals(cont.getUuid())) {
containerDialog.setCurrentContainerDTO(new ContainerDto());
addToPopupSlot(containerDialog);
break;
}
}
} catch (NumberFormatException e) {
Log.debug("id cannot be retrieved from URL");
}
}
}
But when revealPlace is called, the URL in the browser stays the same and the default presenter (Home) is shown instead.
When i print the request, it seems to be fine:
PlaceRequest(nameToken=containersPage, params={action=editContainer, containerEditId=8fa5f730-fe0f-11e3-a3ac-0800200c9a66})
And my NameTokens are like this:
public class NameTokens {
public static final String homePage = "!homePage";
public static final String containersPage = "!containersPage";
public static final String devicesPage = "!devicesPage";
public static String getHomePage() {
return homePage;
}
public static String getDevicesPage() {
return devicesPage;
}
public static String getContainersPage() {
return containersPage;
}
}
What did i miss? Thanks!
In your original code, when constructing your PlaceRequest, you forgot the '!' at the beginning of your nametoken.
.nameToken("containersPage")
while your NameTokens entry is
public static final String containersPage = "!containersPage";
As you noted, referencing the constant in NameTokens is less prone to such easy mistakes to make!
Sometimes the problem exists "between the ears". If i avoid strings but use the proper symbol from NameTokens like
PlaceRequest request = new PlaceRequest.Builder()
.nameToken(NameTokens.containersPage)
.with("action","editContainer")
.with("containerEditId", selectedContainerDto.getUuid().toString())
.build();
it works just fine. Sorry!
I need to customize serialization of a POJO in Jackson so that I can apply filter on the properties based on user input
I applied the following annotations on the POJO.
#JsonFilter("userFilter")
#JsonSerialize(using = UserSerializer.class)
The custom serializer class is as below.
public class UserSerializer extends JsonSerializer<User> {
#Override
public void serialize(User value, JsonGenerator jgen,
SerializerProvider provider) throws IOException,
JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
SimpleFilterProvider sfp = new SimpleFilterProvider();
// create a set that holds name of User properties that must be serialized
Set userFilterSet = new HashSet<String>();
userFilterSet.add("firstName");
userFilterSet.add("corporateOrgs");
userFilterSet.add("rights");
userFilterSet.add("requirements");
sfp.addFilter("userFilter",SimpleBeanPropertyFilter.filterOutAllExcept(userFilterSet));
// create an objectwriter which will apply the filters
ObjectWriter writer = mapper.writer(sfp);
String json = writer.writeValueAsString(value);
}
}
I can see that Jackson is trying to serialize the POJO using the custom serializer defined. However it ends up in infinite recursion/stackoverflow as writer.writeValueAsString(value) ends up calling the custom serializer again.
Obviously I have not got some basic stuff right here. If the filtering is done outside the serialize method (for example in a method called from main() ), filtering works as expected.
can anyone please provide insight/link to documentation on how to make use of custom serialization to leverage filtering.
Fields can be filtered out with JsonFilter, or you can create a custom JsonSerialize serializer that writes out only certain fields.
Independent of the use of a JsonFilter, the attempt to recursively reserialize the same object to be serialized (first parameter of the overwritten serialize method) in a user-defined serializer with an object mapper will result in an infinite loop. Instead, in a custom serializer you would rather use the JsonGenerator methods (second parameter of the overridden serialize method) to write out field name/values.
In the following answer both variants (#JsonFilter and #JsonSerialize) are demonstrated, where only a part of the available fields are serialized to JSON.
#JsonFilter
To apply filters to properties based on user input, you do not need to extend JsonSerializer. Instead, you annotate the POJO with JsonFilter and just apply the filtering.
A self-contained example based on your code would look like this:
package com.software7.test;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter;
import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider;
import java.util.HashSet;
import java.util.Set;
public class Main {
public static void main(String[] args) {
Main m = new Main();
try {
m.serialize();
} catch (JsonProcessingException e) {
e.printStackTrace();
}
}
void serialize() throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
SimpleFilterProvider sfp = new SimpleFilterProvider();
Set<String> userFilterSet = new HashSet<>();
userFilterSet.add("firstName");
userFilterSet.add("corporateOrgs");
userFilterSet.add("rights");
userFilterSet.add("requirements");
sfp.addFilter("UserFilter",
SimpleBeanPropertyFilter.filterOutAllExcept(userFilterSet));
mapper.setFilterProvider(sfp);
User user = new User("Brownrigg", "Don", "none", "+rwx", "n/a",
"some", "superfluous", "properties");
System.out.println(user);
System.out.println(">>>> serializing >>>>");
String s = mapper.writeValueAsString(user);
System.out.println(s);
}
}
User POJO
package com.software7.test;
import com.fasterxml.jackson.annotation.JsonFilter;
#JsonFilter("UserFilter")
public class User {
public String lastName;
public String firstName;
public String corporateOrgs;
public String rights;
public String requirements;
public String a, b, c;
public User(String lastName, String firstName, String corporateOrgs, String rights, String requirements,
String a, String b, String c) {
this.lastName = lastName;
this.firstName = firstName;
this.corporateOrgs = corporateOrgs;
this.rights = rights;
this.requirements = requirements;
this.a = a;
this.b = b;
this.c = c;
}
#Override
public String toString() {
return "User{" +
"lastName='" + lastName + '\'' +
", firstName='" + firstName + '\'' +
", corporateOrgs='" + corporateOrgs + '\'' +
", rights='" + rights + '\'' +
", requirements='" + requirements + '\'' +
", a='" + a + '\'' +
", b='" + b + '\'' +
", c='" + c + '\'' +
'}';
}
}
Test
The debug output of the above program would look like this:
User{lastName='Brownrigg', firstName='Don', corporateOrgs='none', rights='+rwx', requirements='n/a', a='some', b='superfluous', c='properties'}
>>>> serializing >>>>
{"firstName":"Don","corporateOrgs":"none","rights":"+rwx","requirements":"n/a"}
The test is successful! As you can see, the properties lastName, a, b and c are removed.
#JsonSerialize Alternative
If you want to use a customer serializer instead you can do like so:
Replace the annotation:
#JsonFilter("UserFilter")
with
#JsonSerialize(using = UserSerializer.class)
but do not use both.
The UserSerializer class could look like this:
package com.software7.test;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import java.io.IOException;
public class UserSerializer extends JsonSerializer<User> {
#Override
public void serialize(User user, JsonGenerator jsonGenerator, SerializerProvider serializerProvider)
throws IOException, JsonProcessingException {
jsonGenerator.writeStartObject();
jsonGenerator.writeObjectField("firstName", user.firstName);
jsonGenerator.writeObjectField("corporateOrgs", user.corporateOrgs);
jsonGenerator.writeObjectField("rights", user.rights);
jsonGenerator.writeObjectField("requirements", user.requirements);
jsonGenerator.writeEndObject();
}
}
Finally, the serialization method would look like this:
void serialize() throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
User user = new User("Brownrigg", "Don", "none", "+rwx", "n/a",
"some", "superfluous", "properties");
System.out.println(user);
System.out.println(">>>> serializing >>>>");
String s = mapper.writeValueAsString(user);
System.out.println(s);
}
The result would be the same in this example. Which variant is better suited depends on the specific use case or personal preferences.
How to output a json object of Request.CreateResponse method?
the below code output the json string
"{RowCount:15}"
,the string is not a json ojbect,it should use eval() method of javscript to convert to json object ,I want the server side return the json object directly,
It should return
{RowCount:15}
that's a json object.
Code
public class PagedDataAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
string jsonRowCount = "{RowCount:10}";
actionExecutedContext.Response = actionExecutedContext.Request.CreateResponse(System.Net.HttpStatusCode.OK, jsonRowCount,System.Net.Http.Formatting.JsonMediaTypeFormatter.DefaultMediaType);
}
}
Instead of using a string, use an anonymous object:
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
var rowCount = new { RowCount = 10 };
actionExecutedContext.Response = actionExecutedContext.Request.CreateResponse(
HttpStatusCode.OK,
rowCount,
JsonMediaTypeFormatter.DefaultMediaType
);
}