REST Web service JSON format - java

I am trying to create a REST web service that returns the details of a user.
Here is my code:
//Actual web service methods implemented from here
#GET
#Path("login/{email}/{password}")
#Produces("application/json")
public Tourist loginUser(#PathParam("email") String email, #PathParam("password") String password) {
List<Tourist> tourists = super.findAll();
for (Tourist tourist : tourists) {
if (tourist.getEmail().equals(email) && tourist.getPassword().equals(password)) {
return tourist;
}
}
//if we got here the login failed
return null;
}
This produces the following JSON:
{
"email": "adrian.olar#email.ro",
"fname": "Adrian",
"lname": "Olar",
"touristId": 1
}
What i need is:
{"tourist":{
"email": "adrian.olar#email.ro",
"fname": "Adrian",
"lname": "Olar",
"touristId": 1
}
}
What would i need to add to my code to produce this?

If you really want to wrap a Tourist into another object, you can do this.
Tourist.java:
package entities;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement
public class Tourist {
int touristId;
String email;
String fname;
String lname;
TouristWrapper.java:
package entities;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement
public class TouristWrapper {
Tourist tourist;
SOResource.java:
package rest;
import entities.Tourist;
import entities.TouristWrapper;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
#Path("/so")
public class SOResource {
#GET
#Path("/tourists/{id}")
#Produces("application/json")
public TouristWrapper loginUser(#PathParam("id") int id) {
Tourist tourist = new Tourist(id, "foo#example.com", "John", "Doe");
TouristWrapper touristWrapper = new TouristWrapper(tourist);
return touristWrapper;
}
}
I have simplified your usecase but you get the point: No Tourist is returned but a TouristWrapper. The JSON returned is this:
{
"tourist": {
"email": "foo#example.com",
"fname": "John",
"lname": "Doe",
"touristId": 1
}
}

Related

Embedded and Embeddable data not stored in the database

I am Learning java-spring boot and i was able to store the normal data in db. but i wasn't able to store the complex json data.
the json data:
{
"id": 1,
"name": "Leanne Graham",
"address": {
"street": "Kulas Light",
"city": "Gwenborough"
}
}
User.java
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Data;
#Data
#AllArgsConstructor
#Entity
#Table(name = "User_tbl")
public class User {
#Id
#GeneratedValue( strategy = GenerationType.AUTO )
private Long id;
private String name;
#Embedded
#Column(name = "Address")
private Address address;
}
Address.java
import jakarta.persistence.Embeddable;
import lombok.AllArgsConstructor;
import lombok.Data;
#Data
#AllArgsConstructor
#Embeddable
public class Address {
private String street;
private String city;
}
UserController.java
import com.example.JsonParser.model.User;
import com.example.JsonParser.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
#RestController
public class UserController {
#Autowired
private UserService userService;
#GetMapping("/list")
public Iterable<User> list() {
return userService.list();
}
#PostMapping("/add")
public User save(User user){
return userService.add(user);
}
}
UserRepository.java
import com.example.JsonParser.model.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
#Repository
public interface UserRepository extends JpaRepository<User,Long> {
}
UserService.java
import com.example.JsonParser.model.User;
import com.example.JsonParser.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
#Service
public class UserService {
#Autowired
private UserRepository repo;
public Iterable<User> list() {
return repo.findAll();
}
public Iterable<User> save(List<User> users) {
return repo.saveAll(users);
}
public User add(User user) {
repo.save(user);
return user;
}
}
application.yml
spring:
h2:
console:
enabled: 'true'
datasource:
url: jdbc:h2:mem:Ramesh
jpa:
defer-datasource-initialization: 'true'
when i send the post request with json data
{
"id": 1,
"name": "Leanne Graham",
"address": {
"street": "Kulas Light",
"city": "Gwenborough"
}
}
i got response as
{
"id": 1,
"name": null,
"address": null
}
H2 db:
also, the db is empty what i should modify or add in order to store the data?
The first thing is that the data from the request is not reaching the Controller. If you put a breakpoint in your save method you can see that all the attributes inside the User will be null. So the first thing you need to do is to annotate the method argument with this #RequestBody, so automatically the JSON data will be converted to your Bean (given that the fields are having the same name).
#PostMapping("/add")
public User save(#RequestBody User user){
return userService.add(user);
}
Second thing is that both your User and Address class should be annotated with #NoArgsConstructor.
So once you've done both the issue will be solved, and data will be saved and retrieved properly.
As you have created Two Entity Classes. First, you have to save the Address and then take Address Instance and set it in the User Entity class and then save it.
OR
Make address as a string instead of Entity class and Try to Pass the data as JSON String to the controller so that I will save it as JSON String
public class User {
#Id
#GeneratedValue( strategy = GenerationType.AUTO )
private Long id;
private String name;
private String address;
}
{
"id": 1,
"name": "Leanne Graham",
"address": "{ "street": "Kulas Light", "city": "Gwenborough" }"
}

New Rest API in Rest Extender not working in Liferay

I have Create one module of type rest in Liferay7 Community Edition. The one application class created with some predefined rest-api.I have written my own api.but the api written by me are not working only predefined api are working. Please find my code below:
package com.codemaster.application;
import java.util.Collections;
import java.util.Set;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Application;
import org.osgi.service.component.annotations.Component;
#ApplicationPath("/greetings")
#Component(immediate = true, service = Application.class)
public class ClickRestApplication extends Application {
public Set<Object> getSingletons() {
return Collections.<Object>singleton(this);
}
#GET
#Produces("text/plain")
public String working() {
return "It works!";
}
#GET
#Path("/morning")
#Produces("text/plain")
public String hello() {
return "Good morning!";
}
#GET
#Path("/morning/{name}")
#Produces("text/plain")
public String morning(
#PathParam("name") String name,
#QueryParam("drink") String drink) {
String greeting = "Good Morning " + name;
if (drink != null) {
greeting += ". Would you like some " + drink + "?";
}
return greeting;
}
#GET
#Path("/demo")
#Produces("text/plain")
public String verify() {
return "Verify User!";
}
#GET
#Path("/dummy")
#Produces("text/plain")
public String dummy()
{
return "Dummy Response";
}
}
What is the issue in my code?

How to provide completely custom JSON for example in Swagger?

I have Java endpoint which receives json-deserializable object. Unfortunately, Swagger is unable to auto-generate good example for it. Is it possible to provide completely custom JSON for an example?
Example is below, regard class Body. It has two fields.
One field is a Set. I want to provide some example list of values for it. I can't use example parameter for this.
Another field is a Parent. It can contain one of two of subclessed, Child1 and Child2. Springfox generates me
{
"parent": {
"#child#": "string"
},
"tags": "[\"tag1\", \"tag2\"]"
}
and I can't send this value (it's incorrect serialization). While I want to have
{
"parent": {
"#child#": "1",
"field1": "value of field 1"
},
"tags": ["tag1", "tag2"]
}
The code:
package com.example.demo;
import java.io.IOException;
import java.util.Set;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.databind.DatabindContext;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.annotation.JsonTypeIdResolver;
import com.fasterxml.jackson.databind.jsontype.impl.TypeIdResolverBase;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.oas.annotations.EnableOpenApi;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
#RestController
#SpringBootApplication
#Configuration
#EnableOpenApi
public class DemoApplication {
#PostMapping(value = "/create", consumes = MediaType.APPLICATION_JSON_VALUE)
public Body create(#RequestBody Body body) {
return body;
}
#Bean
public Docket docket() {
return new Docket(DocumentationType.OAS_30)
.select()
.apis(RequestHandlerSelectors.basePackage(DemoApplication.class.getPackageName()))
.paths(PathSelectors.any())
.build()
//.apiInfo(apiInfo())
//.securitySchemes(Collections.singletonList(apiKey()))
//.protocols(getProtocols(systemSettings))
;
}
public static class Body {
#ApiModelProperty(example = "[\"tag1\", \"tag2\"]")
public Set<String> tags;
public Parent parent;
}
#JsonTypeInfo(use = JsonTypeInfo.Id.CUSTOM, property = "#child#", include = JsonTypeInfo.As.EXISTING_PROPERTY, visible = true)
#JsonTypeIdResolver(MyTypeIdResolver.class)
#ApiModel(discriminator = "#child#")
public static class Parent {
final String childTypeNumber;
#JsonProperty("#child#")
public String childTypeNumber() {
return childTypeNumber;
}
public Parent(String childTypeNumber) {
this.childTypeNumber = childTypeNumber;
}
}
public static class MyTypeIdResolver extends TypeIdResolverBase {
private JavaType superType;
#Override
public void init(JavaType baseType) {
superType = baseType;
}
#Override
public String idFromValue(Object value) {
return null;
}
#Override
public String idFromValueAndType(Object value, Class<?> suggestedType) {
return null;
}
#Override
public JsonTypeInfo.Id getMechanism() {
return null;
}
#Override
public JavaType typeFromId(DatabindContext context, String id) throws IOException {
char c = id.charAt(0);
Class<?> subType = null;
switch (c) {
case '1':
subType = Child1.class;
break;
case '2':
subType = Child2.class;
break;
default:
throw new RuntimeException("Invalid Child type");
}
return context.constructSpecializedType(superType, subType);
}
}
public static class Child1 extends Parent {
public String field1;
public Child1() {
super("1");
}
}
public static class Child2 extends Parent {
public String field2;
public Child2() {
super("2");
}
}
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
From what I understand, you want swagger to display the resource returned by the endpoint.
If so, this is the solution:
#Operation(summary = "create new resource",
description = "create resourcey completely", responses = {
#ApiResponse(responseCode = "200",
description = "createresource",
content = {#Content(mediaType = "application/json",
schema = #Schema(implementation = Body.class))})
#PostMapping(value = "/create", consumes = MediaType.APPLICATION_JSON_VALUE)
public Body create(#RequestBody Body body) {
return body;
}
So that the controller does not have so many things left, what is done is to create the controller interface with all the annotations on the method signature, then your controller will implement the interface that already has all the documentation annotations.

How to get around error "Unrecognized field "Name, not marked as ignorable", to insert JSON data into H2 database with Spring?

I am trying to insert the following json data into H2 database with Spring by following the process shown in this Dan Vega video on YouTube. But, I get the following error:
Error:
Unable to save products: Unrecognized field "Name" (class com.saurabhsomani.domain.Product), not marked as ignorable (6 known properties: "salesCount", "price", "name", "category", "cust_rating", "id"])
at [Source: (BufferedInputStream); line: 2, column: 12] (through reference chain: java.util.ArrayList[0]->com.saurabhsomani.domain.Product["Name"])
Could you please help me fix this issue? Below are the code details:
My JSON (product.json) looks like:
[{
"Name": "P1",
"ID": 1,
"Price": 970,
"SalesCount": 300,
"Category": "A",
"Cust_Rating": 3.7
},
{
"Name": "P2",
"ID": 2,
"Price": 1170,
"SalesCount": 718,
"Category": "A",
"Cust_Rating": 3.8
},
{
"Name": "P3",
"ID": 3,
"Price": 1090,
"SalesCount": 1253,
"Category": "A",
"Cust_Rating": 0.5
}
]
Project Structure looks like:
Project Structure
JsondbApplication.java
package com.saurabhsomani;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.saurabhsomani.domain.Product;
import com.saurabhsomani.service.ProductService;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
#SpringBootApplication
public class JsondbApplication {
public static void main(String[] args) {
SpringApplication.run(JsondbApplication.class, args);
}
#Bean
CommandLineRunner runner(ProductService productService){ //will help us when the application starts up
return args -> { //functional interface
//read json and write to db
ObjectMapper mapper = new ObjectMapper();
//We want a list of products
TypeReference<List<Product>> typeReference = new TypeReference<List<Product>>(){};
InputStream inputStream = TypeReference.class.getResourceAsStream("/json/product.json");
try{
//mapper helps us map json structure to the domain object
List<Product> products = mapper.readValue(inputStream, typeReference);
productService.save(products);
System.out.println("Products Saved!");
} catch (IOException e){
System.out.println("Unable to save products: " + e.getMessage());
}
};
}
}
ProductController.java
package com.saurabhsomani.controller;
import com.saurabhsomani.domain.Product;
import com.saurabhsomani.service.ProductService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
#RestController
#RequestMapping("/products")
public class ProductController {
//no business logic in controller
private ProductService productService;
//constructor
public ProductController(ProductService productService) {
this.productService = productService;
}
public ProductService getProductService() {
return productService;
}
#GetMapping("/list")
public Iterable<Product> list(){
return productService.list();
}
}
Product.java
package com.saurabhsomani.domain;
import lombok.AllArgsConstructor;
import lombok.Data;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
#Data
#AllArgsConstructor
#Entity
public class Product {
#Id
#GeneratedValue( strategy = GenerationType.AUTO)
private String name;
private int id;
private int price;
private int salesCount;
private String category;
private double cust_rating;
public Product(){
}
}
ProductService.java
package com.saurabhsomani.service;
import com.saurabhsomani.domain.Product;
import com.saurabhsomani.repository.ProductRepository;
import org.springframework.stereotype.Service;
import java.util.List;
#Service
public class ProductService {
private ProductRepository productRepository;
public ProductService(ProductRepository productRepository) {
this.productRepository = productRepository;
}
public Iterable<Product> list(){
return productRepository.findAll();
}
//to save one product
public Product save(Product product){
return productRepository.save(product);
}
//to save list of products
public void save(List<Product> products) {
productRepository.saveAll(products);
}
}
ProductRepository
package com.saurabhsomani.repository;
import com.saurabhsomani.domain.Product;
import org.springframework.data.repository.CrudRepository;
public interface ProductRepository extends CrudRepository <Product, String>{
}
In Product class you need to add Jackson's #JsonProperty annotation on properties relevant to attributes of source JSON as they are not identical (but differently cased)
public class Product {
...
#JsonProperty("Name")
private String name;
#JsonProperty("Price")
private int price;
#JsonProperty("Cust_Rating")
private double cust_rating;
// and others
}
P.S. try to avoid underscores in names outside of unit tests and stick to Java Code Conventions (https://google.github.io/styleguide/javaguide.html)

Get JSON data from a request and craft a JSON response using Java Jersey and Jackson

I'm a beginner trying to learn about RESTful API in Java. I have created a Dynamic Web project in Eclipse and tried to receive JSON data in request.
#Path("/test")
public class TestAPI {
#POST
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public String sayHello(User user) {
String name = user.getName();
return name;
}
}
#XmlRootElement(name = "user")
#XmlAccessorType(XmlAccessType.FIELD)
class User{
private String name;
public User() {}
#XmlElement
public void setName(String s) {
this.name = s;
}
public String getName() {
return name;
}
public String toString(){
return "{\"name\": "+name+"}";
}
}
In this code, I have tried to create a class User which only have one attribute name. I'm trying to send the name as JSON in request and retrieve the name from JSON.
HTTP Status 500 - javax.ws.rs.ProcessingException: Error deserializing
object from entity stream
error.
Can anyone tell me what's wrong with my code?
Thanks in advance.
Edit: Import section is
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
Try removing all the xml tags from your POJO and run.
Like this:
class User{
private String name;
public void setName(String s) {
this.name = s;
}
public String getName() {
return name;
}
public String toString(){
return "{\"name\": "+name+"}";
}
}
Request JSON:
{"name" : "Your Name"}
Hope it helps.

Categories