Converting a Java class with nested array of Java classes to JSON - java

Is there a convenient way to convert a Java class with a nested array of Java classes into JSON? For instance I want to convert an instance f the following class to JSON:
public class Students {
private final String serial_no;
private final class InnerData {
private final String[] strs;
private final String name;
private final String city;
}
private final StudentList[] students;
}
as
{
"serial_no" : null,
students : [
{
"strs" : ["athlete", "grammarian"],
"name" : "John Smith",
"city" : "Auckland"
},
{
"strs" : ["postmaster", "swimmer"],
"name" : "Jane Doe",
"city" : "Sydney"
}
]
}
What is the best way to do this in Spring? The examples I have come across seem to be simple classes so far with no nesting.

To return an java object in JSON form from an spring objects requires two simple configurations:
1) Adding 'jackson-mapper-asl' dependency to the classpath
2) Add #ResponseBody annotation to the controller's method 
1) Adding 'jackson-mapper-asl' dependency to the classpath
In a spring mvc project we need to add a 'jackson-mapper-asl' dependency to the pom.xml file, and object to json conversion is done by default.
<dependency>   <groupId>org.codehaus.jackson</groupId>   <artifactId>jackson-mapper-asl</artifactId>   <version>1.9.10</version>  </dependency>  
2) Add #ResponseBody annotation to the controller's method
Second thing we need to do is to use '#ResponseBody' annotation against the controller's method. This will make spring understand that method return value should be bound to the web response body.
#RequestMapping("studentlist")   public 
#ResponseBody   List<Student> getStudentList() {    List<Student> studentList = new ArrayList<Student>();    studentList.add(new Student(23, "Meghna", "Naidu", "meghna#gmail.com",      "8978767878"));    studentList.add(new Student(3, "Robert", "Parera", "robert#gmail.com",      "8978767878"));    studentList.add(new Student(93, "Andrew", "Strauss",      "andrew#gmail.com", "8978767878"));    studentList.add(new Student(239, "Eddy", "Knight", "knight#gmail.com",      "7978767878"));      return studentList;   
} 

Related

How to use WebMvcLinkBuilder with repository's findById?

I'm trying to use Spring Data Rest to implement a full set of services for about 60 entities. Right now, I'm getting by with just letting Spring use my repositories rather than implementing controllers, which is great!
The data I'm having to model isn't ideal--I'd prefer to have customerId come as part of the order object.
{
"tenantId": 42,
"id": "00000001",
"customer": {
"tenantId": 42,
"id": "CUST001",
"name": "Arthur Dent"
}
}
I have the ID for a related entity as a property on my JSON object.
public class Order {
Long tenantId;
String id;
String customerId;
}
I don't really want to pull the full Customer entity and all of the other related entities and place them as members on my Order object. Instead, I'd just like to add some links to the _links collection.
I believe I've figured out WebMvcLinkBuilder finally and I have the basic idea in place. However, JpaRepository.findById returns a java.util.Optional.
#Bean
public RepresentationModelProcessor<EntityModel<Order>> orderProcessor() {
return new RepresentationModelProcessor<EntityModel<Order>>() {
#Override
public EntityModel<Order> process(final EntityModel<Order> model) {
final CustomerRepository controller = WebMvcLinkBuilder.methodOn(CustomerRepository);
final CustomerId id = new CustomerId(model.getContent().getTenantId(), model.getContent().getCustomerId());
model.add(WebMvcLinkBuilder.linkTo(controller.findById(id)).withRel("customer"));
return model;
}
};
}
The error I get is:
Could not generate CGLIB subclass of class java.util.Optional: Common causes of this problem include using a final class or a non-visible class; nested exception is java.lang.IllegalArgumentException: Cannot subclass final class java.util.Optional
How can I add a link to my resource?

Return an array of objects with fieldName in spring boot

I am new to springboot. My requirement is as below.
I have carModel class as below.
#Data
public class CarModel {
private modelName;
private available;
}
Now I have a rest endpoint that returns the list of objects. So the resource looked something like this.
#GetMapping("/models")
public List<CarModel> getModels(){
//Resource Body
}
But this return an array of objects in json, with no field name. But I need the the json , something like this:
{ "AllModels" : [ { "modelName" : "Ferrari", "available" : "Yes"} , {"modelName": "Tesla" , "available" : "Yes"} ]
How can I do this in spring boot? I do know of a solution by defining one more wrapper class with list of CarModel objects in it. But is there any better way of doing it(Something like any annotations, etc.,)
Thanks!
You can use ResponseEntity method that is already there available in Spring MVC. Would something like this work for you?
#GetMapping("/models")
public ResponseEntity<List<CarModel>> getCars() {
List<CarModel> carModels = service.methodThatReturnsListOfCarModels();
return ResponseEntity.ok().body(new HashMap<>(){{put("AllModels", carModels);}});
}

Property and Alias mapping don't seem to work

I have a simple json like this
{
"someReports":[
{
"reportName": "PR123",
"fields": [
]
},
{
"reportName": "PR234",
"fields": []
}
]
}
I have a class that looks somewhat like this inside which getSomeReports() is defined.
class AHeckLotOfReports {
private String someString;
private List<SomethingElse> some;
..
#JsonProperty("someReports")
private List<SomeReports> someReports;
}
//POJO:
class SomeReport {
String reportName;
List<Field> fields;
...
}
//REST Controller looks like this. some injection code is cleaned up
#Api(tags = “SomeReport”)
#Controller
#ThreadSafe
#RequestMapping(“/report/v2")
public class ReportController{
#ApiOperation(value = "Create a new report.”)
#RequestMapping(value = “/report”, method = RequestMethod.POST)
#ResponseBody
public ReportResponse addReport(
#Nonnull final AuthorizationToken authorizationToken,
#Nonnull#RequestBody final AHeckLotOfReports reportRequest) {
final Report report=this.reportService.addReport(
authorizationToken,
reportRequest.getName(),
reportRequest.isEnabled(),
reportRequest.getConfiguration().or(ReportConfiguration.empty()),
reportRequest.getNewConfiguration(),
reportRequest.getDefinition());
return ReportResponse.fromReport(report);
}
I haven't been able to get this working. I do get the structure intact but reportName comes up blank, the fields array comes up empty.
I have tried JsonAlias("someReports","some_reports") and that seems to make no difference.
Anything comes out as an obvious "duh" in this ?
EDIT: My apologies, I did realize I have not provided the entire context. I AM able to deserialize the simple POJO with ObjectMapper. But the class AHeckLotOfReports is used as request object in REST endpoint for a POST and this is where the problem surfaces
Software: jackson.core 2.9.9, jackson.datatype 2.9.8 and JDK 8.0, Spring-Boot 2.2.6

spring boot expand configuration properties metadata json "hints" for Map not work

I want to expand configuration metadata in my project just as mentioned in the documentation.
Usually, I can use the spring-boot-configuration-processor dependency to generate my own metadata. But in this case, I'm using Map<String, Foo> properties in my properties, and I want the IDE to show code hints when using these propertie.
Let me show you the code.
FooProperties
#ConfigurationProperteis("server.worker")
public class FooProperties {
private int workerCount;
private int subWorkerCount;
private int limit;
#NestedConfigurationProperty
private Map<String, BooProperties> group = new HashMap<>();
//getter and setter
}
BooProperties
public class BooProperties{
private int workerCount;
}
additional-spring-configuration-metadata.json
{
"properties":[{
"name": "server.worker.group",
"type":"java.util.Map<java.lang.String,com.FooProperties>",
"description": ".....",
"sourceType":"com.FooProperties"
}],
"hints":[{
"name":"server.worker.group.keys",
"providers":[{
"name":"any"
}]
}, {
"name":"server.worker.group.values",
"providers" : [{
"name":"class-reference"
}]
}]
}
And this is an image of my IDE, not showing any hints:
Is there anything I can change to make this work?
I found the problem.
In my code, I annotated #Import and #Autowird on FooProperties.
When I remove those annotations and use the 'spring-boot-configuration-processor' dependency, It works.
So, that case can work fine.

Can't map second level json value with Spring Webflux Webclient

I am consuming the public API for crypto currencies in Mexico: https://api.bitso.com/v3/available_books/ that returns a json like this one:
"success": true,
"payload": [
{
"book": "btc_mxn",
"minimum_price": "500.00",
"maximum_price": "16000000.00",
"minimum_amount": "0.000075",
"maximum_amount": "500.00000000",
"minimum_value": "5",
"maximum_value": "10000000.00"
},
{
"book": "eth_btc",
"minimum_price": "0.00000100",
"maximum_price": "5000.00000000",
"minimum_amount": "0.00000100",
"maximum_amount": "1000.00000000",
"minimum_value": "0.00000100",
"maximum_value": "2000.00000000"
},
and the code that consumes it with Webclient is:
#Override
public Mono<Coins> getCoins() {
return webClient.get().uri("https://api.bitso.com/v3/available_books/")
.accept(MediaType.APPLICATION_JSON)
.retrieve().bodyToMono(Coins.class);
}
The POJOs that are trying to bind it are:
#Data
public class Coins {
#JsonProperty("success")
private String success;
#JsonProperty("playload")
private List<Coin> playload;
and
#Data
public class Coin {
#JsonProperty("book")
private String book;
#JsonProperty("minimum_amount")
private String minimumAmount;
#JsonProperty("maximum_amount")
private String maximumAmount;
#JsonProperty("minimum_price")
private String minimumPrice;
#JsonProperty("maximum_price")
private String maximumPrice;
#JsonProperty("minimum_value")
private String minimumValue;
#JsonProperty("maximum_value")
private String maximumValue;
So far, it only maps like this
"success": true,
"payload": null
You need to have no-args construct and change the word playload to payload :)
I don't think this is a WebFlux issue, but rather a Jackson + Lombok issue.
What happens if you try to deserialize that payload with raw ObjectMapper?
I think Jackson requires an all args constructor annotated with #JsonCreator or ask Lombok to create a #NoArgConstructor for that class. In any case, rewriting your Coin class as a regular Java class should work.
Also, your Coins class has a typo since it's trying to get playload instead of payload.
FIXED: Typo at property name playload instead of payload

Categories