I have the follow json.
{
foo:{
id:1
},
name:'Albert',
age: 32
}
How can I deserialize to Java Pojo
public class User {
private int fooId;
private String name;
private int age;
}
This is what you need to deserialize, using the JsonProperty annotations in your constructor.
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
public class User {
private int fooId;
private String name;
private int age;
public int getFooId() {
return fooId;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public User(#JsonProperty("age") Integer age, #JsonProperty("name") String name,
#JsonProperty("foo") JsonNode foo) {
this.age = age;
this.name = name;
this.fooId = foo.path("id").asInt();
}
public static void main(String[] args) {
ObjectMapper objectMapper = new ObjectMapper();
String json = "{\"foo\":{\"id\":1}, \"name\":\"Albert\", \"age\": 32}" ;
try {
User user = objectMapper.readValue(json, User.class);
System.out.print("User fooId: " + user.getFooId());
} catch (IOException e) {
e.printStackTrace();
}
}
}
Output:
User fooId: 1
Hope it helps,
Jose Luis
You can do one of the following:
Create a concrete type representing Foo:
public class Foo {
private int id;
...
}
Then in User you would have:
public class User {
private Foo foo;
...
}
Use a Map<String, Integer>:
public class User {
private Map<String, Integer> foo;
...
}
If other callers are really expecting you to have a getFooId and a setFooId, you can still provide these methods and then either delegate to Foo or the Map depending on the option you choose. Just make sure that you annotate these with #JsonIgnore since they aren't real properties.
You can use a very helpful gson google API.
First of all, create these two classes:
User class:
public class User{
Foo foo;
String name;
int age;
//getters and setters
}
Foo class:
public class Foo{
int id;
//getters and setters
}
If you have a example.json file then deserialize it as follow
Gson gson = new Gson();
User data = gson.fromJson(new BufferedReader(new FileReader(
"example.json")), new TypeToken<User>() {
}.getType());
If you have a exampleJson String then deserialize it as follow
Gson gson = new Gson();
User data = gson.fromJson(exampleJson, User.class);
Related
I have these objects:
public class Person {
private String name;
private String age;
private List<Job> list = new ArrayList<>();
//getters and setters
}
public class Job {
private String title;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
using Jackson in main:
ObjectMapper mapper = new ObjectMapper();
mapper.activateDefaultTypingAsProperty( new DefaultBaseTypeLimitingValidator(),
ObjectMapper.DefaultTyping.NON_FINAL, "class");
String json2 = mapper.writeValueAsString( person );
json2:
{
"class":"com.johnson.testing.Person",
"name":"Brandon Johnson","age":50,
"list":["java.util.ArrayList",
[{"class":"com.johnson.testing2.Job",
"title":"work"}]]
}
I want the "class" key but I do not want the "java.util.ArrayList" field. I
am using Jackson to serialize nested objects that are in libraries. I do not have
access to the Java Objects to annotate the classes. How can I just have the class
with path added to the many nested objects and not the other stuff?
I have a Entity class something like this:
#Entity
public class Website {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
private String url;
public Website() {
//Constructor
//getters and setters
}
here is the DTO class:
public class WebsiteDto {
private Integer id;
private String name;
private String url;
public WebsiteVo() {
//Constructor
//getters and setters
}
I have the WebsiteMapper something like this:
#Component
public class WebsiteMapper {
public List<WebsiteDto> getWebsiteList() {
return repository.findAll().stream().map(w -> {
WebsiteDto dto = new WebsiteVo(w.getId(), w.getName(), w.getUrl());
return dto;
}).collect(Collectors.toList());
I also have Repository Interface:
public interface WebsiteRepository extends JpaRepository<Website, Integer> {
}
I want now to convert DTO to entity using my class WebsiteMapper. Because I did the conversion in this class. How I can do it?
How about using BeanUtils provided by spring org.springframework.beans.BeanUtils, something like this
public List<WebsiteDto> getWebsiteList() {
return repository.findAll().stream().map(w -> {
WebsiteDto dto = new WebsiteVo();
BeanUtils.copyProperties(w, dto); // copys all variables with same name and type
return dto;
})
.collect(Collectors.toList());
}
Hi I guess you wish to converting your entity to DTO. It's quite simple. Create static methods in your DTO class or any util class. The return type should be your DTO type.
e.g.
public class WebsiteDto {
private Integer id;
private String name;
private String url;
public static WebsiteDto export(Website website) {
// Return a new instance of your website DTO
return new WebsiteDto(
website.getId(),
website.getName(),
website.getUrl()
);
}
public static List<WebsiteDto> export(List<Website> websites) {
// Return a new instance of your website DTO list
return websites.stream().map(website -> {
return new WebsiteDto(
website.getName(),
website.getUrl()
}).collect(Collectors.toList());
}
}
NOTE You can also convert your DTO to entity using similar method.
I have MyEntity class:
#Entity
#Table("entities)
public class MyEntity {
#ID
private String name;
#Column(name="age")
private int age;
#Column(name="weight")
private int weight;
...getters and setters..
}
In #RestController there are 2 #GetMapping methods.
The first:
#GetMapping
public MyEntity get(){
...
return myEntity;
}
The second:
#GetMapping("url")
public List<MyEntity> getAll(){
...
return entities;
}
It's needed to provide:
1. #GetMapping returns entity as it's described in MyEntity class.
2. #GetMapping("url") returns entities like one of its fields is with #JsonIgnore.
UPDATE:
When I return myEntity, client will get, for example:
{
"name":"Alex",
"age":30,
"weight":70
}
I want in the same time using the same ENTITY have an opportunity depending on the URL send to client:
1.
{
"name":"Alex",
"age":30,
"weight":70
}
2.
{
"name":"Alex",
"age":30
}
You could also use JsonView Annotation which makes it a bit cleaner.
Define views
public class View {
static class Public { }
static class ExtendedPublic extends Public { }
static class Private extends ExtendedPublic { }
}
Entity
#Entity
#Table("entities)
public class MyEntity {
#ID
private String name;
#Column(name="age")
private int age;
#JsonView(View.Private.class)
#Column(name="weight")
private int weight;
...getters and setters..
}
And in your Rest Controller
#JsonView(View.Private.class)
#GetMapping
public MyEntity get(){
...
return myEntity;
}
#JsonView(View.Public.class)
#GetMapping("url")
public List<MyEntity> getAll(){
...
return entities;
}
Already explained here:
https://stackoverflow.com/a/49207551/3005093
You could create two DTO classes, convert your entity to the appropriate DTO class and return it.
public class MyEntity {
private String name;
private int age;
private int weight;
public PersonDetailedDTO toPersonDetailedDTO() {
PersonDetailedDTO person = PersonDetailedDTO();
//...
return person;
}
public PersonDTO toPersonDTO() {
PersonDTO person = PersonDTO();
//...
return person;
}
}
public class PersonDetailedDTO {
private String name;
private int age;
private int weight;
}
public class PersonDTO {
private String name;
private int age;
}
#GetMapping
public PersonDTO get() {
//...
return personService.getPerson().toPersonDTO();
}
#GetMapping("/my_url")
public PersonDetailedDTO get() {
//...
return personService.getPerson().toPersonDetailedDTO();
}
EDIT:
Instead of returning an Entity object, you could serialize it as a Map, where the map keys represent the attribute names. So you can add the values to your map based on the include parameter.
#ResponseBody
public Map<String, Object> getUser(#PathVariable("name") String name, String include) {
User user = service.loadUser(name);
// check the `include` parameter and create a map containing only the required attributes
Map<String, Object> userMap = service.convertUserToMap(user, include);
return userMap;
}
As an example, if you have a Map like this and want
All Details
userMap.put("name", user.getName());
userMap.put("age", user.getAge());
userMap.put("weight", user.getWeight());
Now if You do not want to display weight then you can put only two
parameters
userMap.put("name", user.getName());
userMap.put("age", user.getAge());
Useful Reference 1 2 3
We currently have some mixins for our data objects in order to keep annotations out of the data objects. So for example
public class SomeDataObj {
private int a;
public int getA() { return this.a; }
public void setA(final int a) { this.a = a; }
}
public interface SomeDataObjMixin {
#JacksonXmlElementWrapper(useWrapping = false)
#JacksonXmlProperty(localName = "A")
int getA();
#JacksonXmlElementWrapper(useWrapping = false)
#JacksonXmlProperty(localName = "A")
void setA(int a);
}
Then in our object mapper class we have
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
public class OurXmlMapper extends XmlMapper {
public OurXmlMapper(final ConfigurableCaseStrategy caseStrategy) {
setPropertyNamingStrategy(caseStrategy);
setSerializationInclusion(Include.NON_NULL);
//yadda yadda
addMixin(SomeDataObj.class, SomeDataObjMixin.class);
// etc etc
}
However, for various reasons I'd like to add a new annotation to the private field in the data object, not the getter or setter. Is there a way to accomplish this through a mixin to maintain that separation? I tried creating a basic class as a mixin (not an interface) and added the private field with the
new annotation to that. This didn't accomplish what I was looking for. Any ideas?
Using Concrete class as mixin working.
// ******************* Item class *******************
public class Item {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
// ******************* ItemMixIn class *******************
#JacksonXmlRootElement(localName = "item-class")
public class ItemMixIn {
#JacksonXmlProperty(localName = "firstName")
private String name;
}
// ******************* test method *******************
public void test() throws Exception {
ObjectMapper mapper = new XmlMapper();
mapper.addMixIn(Item.class, ItemMixIn.class);
Item item = new Item();
item.setName("hemant");
String res = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(item);
System.out.println(res);
}
Output:
<item-class>
<firstName>hemant</firstName>
</item-class>
I have jackson version 2.9.5.
Let's pretend I have the following XML:
<company name="Sun" country="Atlantis" state="Syracuse" city="Troy">
</company>
With JAXB, and without using third-party extensions such as EclipseLink's #XmlPath, is there a way to unmarshall it into the following POJO structure:
#XmlRootElement
public class Company {
private String name;
private Address address;
// getters and setters
}
public class Address {
private String country;
private String state;
private String city;
// getters and setters
}
company.getAddress().getCountry(); // Atlantis
This particular scenario can be handled using an XmlAdapter:
import javax.xml.bind.annotation.adapters.XmlAdapter;
import java.time.format.DateTimeFormatter;
public class CompanyAdapter extends XmlAdapter<CompantType, Company> {
#Override
public CompanyType marshal(Company in) throws Exception {
CompanyType out = new CompanyType();
out.setName(in.getName());
out.setCountry(in.getAddress().getCountry());
// ...
return out;
}
#Override
public Company unmarshall(CompanyType in) throws Exception {
Company out = new Company();
out.setName(in.getName());
Address add = new Address();
add.setCountry(in.getCountry());
out.setAddress(add);
// ...
return out;
}
}