I have a class called Lookup that has two properties:
public class Lookup {
private String surveyName;
private String GUID;
public Lookup(String name, String guid){
this.surveyName = name;
this.GUID = guid;
}
}
In another class, I have a list of Lookup that I am trying to serialize and save to file. This is how I'm doing it:
List<Lookup> lookup = new ArrayList<Lookup>();
lookup.add(new Lookup("foo","bar"));
XStream serializer = new XStream();
serializer.alias("Lookups",List.class);
String xml = serializer.toXML(lookup);
The XML I end up with is:
<Lookups>
<Lookup>
<GUID>bar</GUID>
</Lookup>
</Lookups>
As you can see, it only serialized the field GUID but not the field surveyName. Why is it ignoring that field?
Are you sure that you don't modify Lookup variable somewhere else. This code runs fine
public class Test {
public static void main(String[] args) {
List<Lookup> lookup = new ArrayList<Lookup>();
lookup.add(new Lookup("foo","bar"));
XStream serializer = new XStream();
serializer.alias("Lookups",List.class);
String xml = serializer.toXML(lookup);
System.out.println(xml);
}
}
class Lookup {
private String surveyName;
private String GUID;
public Lookup(String name, String guid){
this.surveyName = name;
this.GUID = guid;
}
}
Output:
<Lookups>
<Lookup>
<surveyName>foo</surveyName>
<GUID>bar</GUID>
</Lookup>
</Lookups>
Silly me, the mistake was completely on my end. The field name was receiving an empty string, and thus XStream must have been ignoring it.
Related
I have this as a substring. It is a JSON string. I am trying to get the id string from it. I was able to do this by using two indexOf's and then substring the two indexOf's. What is a better solution.
Here is my string
"{"id":"762c094a-4b65-499e-b5b2-de34ef8d726e","createdTimestamp":1605558195131,"username":"sssdv","enabled":false,"totp":false,"emailVerified":false,"firstName":"cdf","lastName":"dddz","email":"hgddf#fdaddf.com","disableableCredentialTypes":[],"requiredActions":[],"notBefore":0,"access":{"manageGroupMembership":true,"view":true,"mapRoles":true,"impersonate":true,"manage":true}}"
And here is my code.
int id = results.indexOf("id");
int cr = results.indexOf("createdTimestamp");
String strId = results.substring(id + 5, cr - 3);
A better solution is to use an actual JSON parser. There are plenty out there. Take a look at this answer on a different question. I would suggest using Gson:
String json = "{\"id\":\"762c094a-4b65-499e-b5b2-de34ef8d726e\",\"createdTimestamp\":1605558195131,\"username\":\"sssdv\",\"enabled\":false,\"totp\":false,\"emailVerified\":false,\"firstName\":\"cdf\",\"lastName\":\"dddz\",\"email\":\"hgddf#fdaddf.com\",\"disableableCredentialTypes\":[],\"requiredActions\":[],\"notBefore\":0,\"access\":{\"manageGroupMembership\":true,\"view\":true,\"mapRoles\":true,\"impersonate\":true,\"manage\":true}}";
Gson gson = new GsonBuilder().setPrettyPrinting().create(); // Create the Gson instance
JsonElement element = gson.fromJson(json, JsonElement.class); // Parse it
String id = element.getAsJsonObject().get("id").getAsString(); // Get your desired element
System.out.println(id);
An even better solution would be to create a class with the fields from your JSON and parse the JSON string to that class:
public class MyObject {
// The names and types of these fields must match the ones in your JSON string
private String id, username, firstName, lastName, email;
private long createdTimestamp;
private boolean enabled, totp, emailVerified;
private String[] disableableCredentialTypes, requiredActions;
private int notBefore;
private Access access;
public String getId() {
return id;
}
// Other getters and setters...
private static class Access {
private boolean manageGroupMembership, view, mapRoles, impersonate, manage;
// ...
}
public static void main(String[] args) throws IOException {
String json = "{\"id\":\"762c094a-4b65-499e-b5b2-de34ef8d726e\",\"createdTimestamp\":1605558195131,\"username\":\"sssdv\",\"enabled\":false,\"totp\":false,\"emailVerified\":false,\"firstName\":\"cdf\",\"lastName\":\"dddz\",\"email\":\"hgddf#fdaddf.com\",\"disableableCredentialTypes\":[],\"requiredActions\":[],\"notBefore\":0,\"access\":{\"manageGroupMembership\":true,\"view\":true,\"mapRoles\":true,\"impersonate\":true,\"manage\":true}}";
Gson gson = new GsonBuilder().setPrettyPrinting().create(); // Create the Gson instance
MyObject object = gson.fromJson(json, MyObject.class); // Parse the string to your data type
System.out.println(object.getId()); // Print the id
}
}
String results = "{\"id\":\"762c094a-4b65-499e-b5b2-de34ef8d726e\",\"createdTimestamp\":1605558195131,\"username\":\"sssdv\",\"enabled\":false,\"totp\":false,\"emailVerified\":false,\"firstName\":\"cdf\",\"lastName\":\"dddz\",\"email\":\"hgddf#fdaddf.com\",\"disableableCredentialTypes\":[],\"requiredActions\":[],\"notBefore\":0,\"access\":{\"manageGroupMembership\":true,\"view\":true,\"mapRoles\":true,\"impersonate\":true,\"manage\":true}}";
String[] parts = results.split("\"");
System.out.println(parts[3]); //gives the id, every time
I am using Jackson library with java 11 so basically I am able to read the below JSON into a string format
{
"schemas":[
"urn:params:core:2.0:User",
"urn:params:core:3.0:User"
],
},
}
here below is the set in which I have to fill the values of schemas from above json
private Set<String> setschemas = null;
right now I am able to read the above json into a string named finaljson , now please advise how can I read the differnt value of schemas from above json string named finaljson and set it to set named setschemas
if (node.has("schemas")) {
// *** here I want to read the differernt value of schemas and set it to a set
// named setschemas
// *****
}
you can create the following classes that represent the json structure
class MyJsonObject {
private AppIdentity appIdentity;
private Set<String> schemas;
private String userName;
}
class AppIdentity {
private String clientId;
private String username;
}
than you can use
final MyJsonObject myJsonObject = new ObjectMapper().readValue(finaljson, MyJsonObject.class); to read the json to JAVA object
so it can manipulated like myJsonObject.schemas.size() > 0 and such...
there are a lot of examples in the internet
*keep in mind, this solution only works when the json structure and fields name are known in advanced
With your approach, this would be simplest one:
if(node.has("schemas")) {
JsonNode schemaNode = node.get("schemas");
Set<String> schemaSet = objectMapper.convertValue(schemaNode, Set.class);
System.out.println("schemaSet" + schemaSet);
}
There are various ways to deal with JSON one is described here
1) You can create a class of JSON structure as follows with help online JSON to POJO convertor (Note:: Add Setters and Getters with help of IDE)
class AppJson {
private Set<AppIdentity> appIdentity;
private Set<String> schemas;
private String userName;
private Manager ManagerObject;
private String division;
private String organization;
private String costCenter;
private String employeeNumber;
}
class AppIdentity {
private String clientId;
private String username;
}
class Manager {
private String value;
private String $ref;
private String displayName;
private String $Ref;
}
2) Use above for object conversion.
ObjectMapper objectMapper = new ObjectMapper();
String jsonString = "{\"appIdentity\":[{\"clientId\":\"9a41763c642\",\"username\":\"XXX\"}],\"schemas\":[\"urn:params:core:2.0:User\",\"urn:params:core:3.0:User\"],\"userName\":\"ajklmnop_699100\",\"manager\":{\"value\":\"string\",\"$ref\":\"sdkoirk\",\"displayName\":\"string\",\"$Ref\":\"sdkweoirk\"},\"division\":\"string\",\"organization\":\"string\",\"costCenter\":\"string\",\"employeeNumber\":\"string\"}\n"
+ "";
AppJson appJson = objectMapper.readValue(jsonString, AppJson.class);
System.out.println("json " + appJson.getSchemas());
Here you will get the schemas.
I have two classes Athlete and Injury, the last one contains Athlete object, when the serialization happens I get the following JSON representation back:
{"id":X,"kindOfInjury":"...","muscle":"...","side":"...","outOfTrainig":Y,"injuryDate":"2018-Jun-02","athlete":{"id":X,"firstName":"...","lastName":"...","age":X,"email":"..."}}
I don't want to get all the information about Athlete - just an id value, like "athleteId":1, instead of getting the entire object representation.
So, I have found that I need to apply my custom Serializer which implements StdSerializer on Injury class. So this is what I got so far:
class InjurySerializer extends StdSerializer<Injury> {
public InjurySerializer() {
this(null);
}
public InjurySerializer(Class<Injury> i) {
super(i);
}
#Override
public void serialize(
Injury value, JsonGenerator jgen, SerializerProvider provider)
throws IOException, JsonProcessingException {
jgen.writeStartObject();
jgen.writeNumberField("id", value.getId());
jgen.writeStringField("kindOfInjury", value.getKindOfInjury());
jgen.writeStringField("muscle", value.getMuscle());
jgen.writeStringField("side", value.getSide());
jgen.writeNumberField("outOfTraining", value.getOutOfTraining());
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MMM-dd");
Date date = new Date();
String ourformat = formatter.format(date.getTime());
jgen.writeStringField("injuryDate", ourformat);
jgen.writeNumberField("athleteId", value.getAthlete().getId());
jgen.writeEndObject();
}
}
And the actual Injury class:
#Entity
#Table(name = "INJURY")
#JsonSerialize(using = InjurySerializer.class)
public class Injury {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "INJURY_ID")
private Long id;
#Column(name = "KIND_OF_INJURY")
private String kindOfInjury;
#Column(name = "MUSCLE")
private String muscle;
#Column(name = "SIDE")
private String side;
#Column(name = "OUT_OF_TRAINING")
private Integer outOfTraining;
#JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MMM-dd")
#Column(name = "INJURY_DATE")
private Date injuryDate;
#ManyToOne
#JoinColumn(name = "ATHLETE_ID")
private Athlete athlete;
So, this solution works, but it looks terrible...
Question is the following:
1) Is there any mechanism which provides me functionality to change the serialization of only ONE property which I really need, instead of writing all this tedious code, where the actual change is only in this line? :
jgen.writeNumberField("athleteId", value.getAthlete().getId());
2) Could you recommend me something to read about Jackson because at this point I have a little bit mess in my head about it?
Thanks for the patience and I'm looking forwards for your responses :)
You can use the Data Transfer Object (DTO) for that purposes.
Create a simple POJO like this:
public class InjuryDTO {
//all other required fields from Injury model...
#JsonProperty("athlete_id")
private Long athleteId;
}
And converter for it:
#Component
public class InjuryToDTOConverter{
public InjuryDTO convert(Injury source){
InjuryDTO target = new InjuryDTO();
BeanUtils.copyProperties(source, target); //it will copy fields with the same names
target.setAthleteId(source.getAthlete().getId());
return target;
}
}
You can use it like that:
#RestController("/injuries")
public class InjuryController {
#Autowired
private InjuryToDTOConverter converter;
#Autowired
private InjuryService injuryService;
#GetMapping
public InjuryDTO getInjury(){
Injury injury = injuryService.getInjury();
return converter.convert(injury);
}
}
The benefit of this approach is that you can have multiple DTOs for different purposes.
You might find it less tedious to use the #JsonIgnore annotation instead of writing a custom serializer. Take this example
public class Person {
private int id;
#JsonIgnore
private String first;
#JsonIgnore
private String last;
#JsonIgnore
private int age;
// getters and setters omitted
}
When Jackson serializes this class, it only includes the "id" property in the resulting JSON.
#Test
void serialize_only_includes_id() throws JsonProcessingException {
final var person = new Person();
person.setId(1);
person.setFirst("John");
person.setLast("Smith");
person.setAge(22);
final var mapper = new ObjectMapper();
final var json = mapper.writeValueAsString(person);
assertEquals("{\"id\":1}", json);
}
You can try manupulating json string using basic string replace method.
I ran your json and converted it to your desired format:
public static void main(String args[]) {
String json = "{\"id\":123,\"kindOfInjury\":\"...\",\"muscle\":\"...\",\"side\":\"...\",\"outOfTrainig\":Y,\"injuryDate\":\"2018-Jun-02\",\"athlete\":{\"id\":456,\"firstName\":\"...\",\"lastName\":\"...\",\"age\":14,\"email\":\"...\"}}";
JsonObject injury = new JsonParser().parse(json).getAsJsonObject();
JsonObject athelete = new JsonParser().parse(injury.get("athlete").toString()).getAsJsonObject();
String updateJson = injury.toString().replace(injury.get("athlete").toString(), athelete.get("id").toString());
updateJson = updateJson.replace("athlete", "athleteId");
System.out.println(updateJson);
}
output:
{"id":123,"kindOfInjury":"...","muscle":"...","side":"...","outOfTrainig":"Y","injuryDate":"2018-Jun-02","athleteId":456}
Dependency:
implementation 'com.google.code.gson:gson:2.8.5'
If you can replace with regex that will be bit more cleaner.
I want to be able to have different names for serialized and deserialized json objects when using jackson in java.
To be a bit more concrete: I am getting data from an API that is using one name standard on their JSON attributes, but my endpoints use a different one, and as I in this case just want to pass the data along I would like to be able to translate the attributes to my name standard.
I have read similar questions on here, but I simply can't seem to get it working.
private String defaultReference;
#JsonProperty(value = "default_reference", access = JsonProperty.Access.WRITE_ONLY)
public void setDefaultReference(String defaultReference)
{
this.defaultReference = defaultReference;
}
#JsonProperty(value = "defaultReference", access = JsonProperty.Access.READ_ONLY)
public String getDefaultReference()
{
return defaultReference;
}
That is my latest attempt. problem with this is that it always returns null, so the setter is not used.
I have also tried:
#JsonProperty(value = "default_reference", access = JsonProperty.Access.WRITE_ONLY)
private String defaultReference;
#JsonProperty(value = "defaultReference", access = JsonProperty.Access.READ_ONLY)
public String getDefaultReference()
{
return defaultReference;
}
This sort of works. It can deserialize default_reference. Problem is that in my JSON response I get both default_reference and defaultReference. Preferably I would only get defaultReference.
Has anyone done anything similar and see what is wrong with what I've tried?
You're on the right track. Here's an example of this working with a test JSON document.
public static class MyClass {
private String defaultReference;
#JsonProperty(value = "default_reference")
public void setDefaultReference(String defaultReference) {
this.defaultReference = defaultReference;
}
#JsonProperty(value = "defaultReference")
public String getDefaultReference() {
return defaultReference;
}
public static void main(String[] args) throws IOException {
ObjectMapper objectMapper = new ObjectMapper();
MyClass instance = objectMapper.readValue("{\"default_reference\": \"value\"}", MyClass.class);
objectMapper.writeValue(System.out, instance);
// Output: {"defaultReference":"value"}
}
}
Another Alternative is
#JsonSetter("default_reference")
public void setDefaultReference(String defaultReference) {
this.defaultReference = defaultReference;
}
#JsonGetter("defaultReference")
public String getDefaultReference() {
return defaultReference;
}
I have an objects class A:
public class A {
private Long id;
private String name;
private String mail;
private String moreData;
// ...
}
class B:
public class B {
private Long id;
private String name;
private String crc;
// ...
}
Can I use jackson to provide field mapping from object A to B copying correspond fields into target object.
I need from object
A {
Long id = 23L;
String name = "name";
String mail = "mail";
String moreData = "moreData";
// ...
}
get as target object
B {
Long id = 23L;
String name = "name";
String crc = mull;
// ...
}
after object mapping processing...
Is it possible implement solution using com.fasterxml.jackson in simple way?
Sure you can. Not withstanding a full understanding of why you want to do this, or that I think there might be more efficient ways than converting to JSON then back, but if you would like to use Jackson, here is what I would do:
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
B b = objectMapper.readValue(objectMapper.writeValueAsString(a), B.class);
Hope this helps. should do the job. The key will be to tell Jackson to not fail on unknown properties so it drops those you are not sure of.