Spring RestController returns 400 Bad Requests for POST Request (used #RequestBody) - spring

I have a simple code snippet below (I did not extends existing repository interface, just try to do things in memory). The GET request works but the POST request returned 400 Bad Request.
I send JSON data to the localhost:8080/v1/products in the below format
{
"productId": 4,
"name": "Amazon Alexa",
"price": 500.0,
"description": "AI device"
}
Controller class
#RestController
#RequestMapping("/v1")
public class ProductController {
private ProductRepository productRepo;
private ProductController(ProductRepository productRepo) {
this.productRepo = productRepo;
}
#GetMapping("/products")
public List<Product> getProduct() {
return productRepo.findAllProducts();
}
#PostMapping("/products")
public List<Product> postProduct(#RequestBody Product product) {
return productRepo.saveProduct(product);
}
}
Repository class
#Repository
public class ProductRepository {
Boolean isLoaded = false;
Product product1 = new Product(1, "Apple TV", 300.0, "This is a TV");
Product product2 = new Product(2, "Samsung Tablet", 900.0, "This is on sale");
Product product3 = new Product(3, "Google Home", 100.0, "Smart AI device");
List<Product> products = new ArrayList<Product>();
private void loadProducts() {
if (!isLoaded) {
products.add(product1);
products.add(product2);
products.add(product3);
isLoaded = true;
}
}
public List<Product> findAllProducts() {
loadProducts();
return products;
}
public List<Product> saveProduct(Product product) {
loadProducts();
products.add(product);
return products;
}
}
Product class with getters/setters omitted, all argument constructor omitted
public class Product {
private int productId;
private String name;
private double price;
private String description;
}
Does anyone know what I missed? Thanks

Related

Spring Boot Rest

i am practicing with spring boot for work with restful applications
I have set a #RestController and #Entity like this
#RestController
#RequestMapping(value = "/api")
public class RestControllerCar {
#Autowired
private CarRepository carRepository;
#RequestMapping(value = "/cars")
public Iterable<Car> getCars() {
return carRepository.findAll();
}
}
and
#Entity
public class Car {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String brand, model, color, registerNumber;
private Integer year, price;
#JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
#ManyToMany(mappedBy = "cars")
private Set<Owner> owners;
public Car() {
}
public Car(String brand, String model, String color, String registerNumber, Integer year, Integer price) {
super();
this.brand = brand;
this.model = model;
this.color = color;
this.registerNumber = registerNumber;
this.year = year;
this.price = price;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public String getModel() {
return model;
}
public void setModel(String model) {
this.model = model;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public String getRegisterNumber() {
return registerNumber;
}
public void setRegisterNumber(String registerNumber) {
this.registerNumber = registerNumber;
}
public Integer getYear() {
return year;
}
public void setYear(Integer year) {
this.year = year;
}
public Integer getPrice() {
return price;
}
public void setPrice(Integer price) {
this.price = price;
}
public Set<Owner> getOwner() {
return owners;
}
public void setOwner(Set<Owner> owners) {
this.owners = owners;
}
when i use postman to http://localhost:8080/cardatabase/api/cars i get a list of Cars
but even if i go to http://localhost:8081/cardatabase/cars, with _embedded on the top
it`s normal?
Thanks!!!!
Is your repository annotated #RestRepository? The _embedded make me think to the kind of output given by a #RestRepository for an array.
#RestRepository auto create all endpoint. As #M.Deinum pointed out, with the data rest starter, if ou remove it , you only have your controller, and not the one generated by #RestRepository.
Two main choices here:
You dont annotate the Repository. Just an interface which implement JpaRepository<YourEntity, TypeOfYourID> and use your controllers
You use only the auto created controllers by #RestRepository.
Or, you can install swagger2 on your project, so, accessing the docs on your browser, you will see all available endpoints, and it may be more clear for you.
With swagger you will also see what is the return type of the endpoint, the parameters etc..
Swagger is really easy to install in a project and to use. (dependencies, one annotation and it's good.. for basic usage).

Getting Null Values in Spring Native Query Project

This is my Data Repository file and i used native query to retrieve all data address(Locations) of Data. I called the function using Postman and I got null outputs of locations. This my first time of using Native query and its really impossible to solve these errors
DataRepository
public interface DataRepository extends JpaRepository<Data, Long> {
#Query(value = "SELECT dataAddress FROM Data")
List<DataProject> getDataAddress();
}
DataServiceImpl
public List<DataProject> getDataAddress() {
return dataRepository.getDataAddress();
}
DataService
List<DataProject> getDataAddress();
DataModel
#Entity
#Table(name = "CCCData")
public class Data {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long dataId;
#Column(name = "DATA_NAME")
private String dataName;
#Column(name ="DATA_ADDRESS")
private String dataAddress;
#Column(name = "DATA_DESC")
private String dataDesc;
#CreationTimestamp
private Date dateOfCreated;
#CreationTimestamp
private Date dateOfUpdated;
public long getDataId() {
return dataId;
}
public void setDataId(long dataId) {
this.dataId = dataId;
}
public String getDataName() {
return dataName;
}
public void setDataName(String dataName) {
this.dataName = dataName;
}
public String getDataAddress() {
return dataAddress;
}
public void setDataAddress(String dataAddress) {
this.dataAddress = dataAddress;
}
public String getDataDesc() {
return dataDesc;
}
public void setDataDesc(String dataDesc) {
this.dataDesc = dataDesc;
}
public Date getDateOfCreated() {
return dateOfCreated;
}
public void setDateOfCreated(Date dateOfCreated) {
this.dateOfCreated = dateOfCreated;
}
public Date getDateOfUpdated() {
return dateOfUpdated;
}
public void setDateOfUpdated(Date dateOfUpdated) {
this.dateOfUpdated = dateOfUpdated;
}
DataProjection
public interface DataProject {
String getDataAddress();
}
DataController
#GetMapping("/data/locations")
public List<DataProject> getDataAddress() {
return dataService.getDataAddress();
}
Postman Output
[
{
"dataAddress": null
},
{
"dataAddress": null
},
{
"dataAddress": null
},
{
"dataAddress": null
}
]
Spring won't return you only address using below query. It still return you DATA object
public interface DataRepository extends JpaRepository<Data, Long> {
#Query(value = "SELECT dataAddress FROM Data")
List<DataProject> getDataAddress();
}
for fetching only DataAddress you need to create a constructor inside Data model for DataAddress only
public Data(String dataAddress) {
this.dataAddress = dataAddress;
}
and your query will look like this:
public interface DataRepository extends JpaRepository<Data, Long> {
#Query(value = "SELECT new Data(dataAddress) FROM Data")
List<DataProject> getDataAddress();
}
Update 1 :
if you need this for other fields with same datatype and then above 'constructor' based method fails. There are some other alternatives:
You can fetch DATA object and use java stream map function to extract only 1 field. data.stream().map((data) -> data.getDataAddress()).collect(Collectors.toList())
You can use native SQL query to fetch only required fields.
#Query(value = "SELECT d.data_address FROM CCCData d", nativeQuery=true)

Spring Boot - Get Data from DB and store it in list and parse it to JSON using jackson

I'm trying to get data from multiple tables and put it in Array List of class, and then convert it to JSON Object.
But when i'm trying to parse it to json using Jackson Object Mapper all the lists are converted as below
Using ObjectMapper().writeValueAsString for deserialization from class objects to json
```{
"College": [
{
"institution": [
{
"instId": "T34",
"Country": "India",
"Code": "T33"
},
{
"instId": "T22",
"Country": "India",
"Code": "T22"
}
],
"Rating": [
{
"star": "4"
"comments": "good"
},
{
"star": "2"
"comments": "ok"
},
}
]
}```
But i want the result as below
{
"College": [
{
"institution": [
{
"instId": "T34",
"Country": "India",
"Code": "T33"
}
],
"Rating": [
{
"star": "4"
"comments": "good"
}
]
},
{
"institution": [
{
"instId": "T22",
"Country": "India",
"Code": "T22"
}
],
"Rating": [
{
"star": "2"
"comments": "ok"
}
]
}
]
}
The above is just an example.
Please help in getting the desired output.
Below are the class files used.
public class AllCollege{
List<College> college = new ArrayList<>();
public List<College> getCollege() {
return college;
}
public void setCollege(List<College> college) {
this.college = college;
}
}
public class College{
private List<Institution> institution = new ArrayList<>();
private List<Rating> rating = new ArrayList<>();
public List<Institution> getInstitution() {
return institution;
}
public void setInstitution(List<Institution> institution) {
this.institution = institution;
}
public List<Rating> getRating() {
return rating;
}
public void setRating(List<Rating> rating) {
this.rating = rating;
}
}
public class Institution {
private String instId;
private String country;
private String code;
public String getInstId() {
return instId;
}
public void setInstId(String instId) {
this.instId = instId;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
}
public class Rating {
private String star;
private String comments;
public String getStar() {
return star;
}
public void setStar(String star) {
this.star = star;
}
public String getComments() {
return comments;
}
public void setComments(String comments) {
this.comments = comments;
}
}
Below is where the data from tables is set into ArrayList and then converted to json string.
session = sessionFactory.openSession();
String sql = "from institution";
Query<InstDto> query = session.createQuery(sql);
List<Institution> configdtoList =query.list();
College alc = new College();
alc.setInstitution(configdtoList);
.
.
.
similarly Rating table.
List<College> clist = new new ArrayList<>();
clist.add(alc);
AllCollege ac = new AllCollege();
ac.setCollege(clist);
String responseJson = new ObjectMapper().writeValueAsString(ac)
class structure as below it will help you to parse:
public class Sample {
#JsonProperty("College")
private List<College> college;
}
public class College {
private List<Institution> institution;
#JsonProperty("Rating")
private List<Rating> rating;
}
public class Rating {
private String comments;
private String star;
}
public class Institution {
#JsonProperty("Code")
private String code;
#JsonProperty("Country")
private String country;
private String instId;
}
I have created an HashMap contains the List<AllCollege> as value and then used json parser which worked as expected.

Expose enums with Spring Data REST

I'm using Spring Boot 1.5.3, Spring Data REST, HATEOAS.
I've a simple entity model:
#Entity
public class User extends AbstractEntity implements UserDetails {
private static final long serialVersionUID = 5745401123028683585L;
public static final PasswordEncoder PASSWORD_ENCODER = new BCryptPasswordEncoder();
#NotNull(message = "The name of the user cannot be blank")
#Column(nullable = false)
private String name;
/** CONTACT INFORMATION **/
private String landlinePhone;
private String mobilePhone;
#NotNull(message = "The username cannot be blank")
#Column(nullable = false, unique = true)
private String username;
#Email(message = "The email address is not valid")
private String email;
#JsonIgnore
private String password;
#Column(nullable = false)
private String timeZone = "Europe/Rome";
#JsonIgnore
private LocalDateTime lastPasswordResetDate;
#Column(nullable = false, columnDefinition = "BOOLEAN default true")
private boolean enabled = true;
#Type(type = "json")
#Column(columnDefinition = "json")
private Roles[] roles = new Roles[] {};
and my enum Roles is:
public enum Roles {
ROLE_ADMIN, ROLE_USER, ROLE_MANAGER, ROLE_TECH;
#JsonCreator
public static Roles create(String value) {
if (value == null) {
throw new IllegalArgumentException();
}
for (Roles v : values()) {
if (value.equals(v.toString())) {
return v;
}
}
throw new IllegalArgumentException();
}
}
I'm creating a client in Angular 4. Spring Data REST is great and expose repository easily return my model HATEOAS compliant:
{
"_embedded": {
"users": [
{
"name": "Administrator",
"username": "admin",
"roles": [
"Amministratore"
],
"activeWorkSession": "",
"_links": {
"self": {
"href": "http://localhost:8080/api/v1/users/1"
},
"user": {
"href": "http://localhost:8080/api/v1/users/1{?projection}",
"templated": true
}
}
},
Like you can see I'm also translating via rest-messages.properties the value of my enums. Great!
My Angular page now needs the complete lists of roles (enums). I've some question:
understand the better way for the server to return the list of roles
how to return this list
My first attemp was to create a RepositoryRestController in order to take advantage of what Spring Data REST offers.
#RepositoryRestController
#RequestMapping(path = "/api/v1")
public class UserController {
#Autowired
private EntityLinks entityLinks;
#RequestMapping(method = RequestMethod.GET, path = "/users/roles", produces = "application/json")
public Resource<Roles> findRoles() {
Resource<Roles> resource = new Resource<>(Roles.ROLE_ADMIN);
return resource;
}
Unfortunately, for some reason, the call to this methods return a 404 error. I debugged and the resource is created correctly, so I guess the problem is somewhere in the JSON conversion.
how to return this list?
#RepositoryRestController
#RequestMapping("/roles")
public class RoleController {
#GetMapping
public ResponseEntity<?> getAllRoles() {
List<Resource<Roles>> content = new ArrayList<>();
content.addAll(Arrays.asList(
new Resource<>(Roles.ROLE1 /*, Optional Links */),
new Resource<>(Roles.ROLE2 /*, Optional Links */)));
return ResponseEntity.ok(new Resources<>(content /*, Optional Links */));
}
}
I was playing around with this and have found a couple of ways to do it.
Assume you have a front end form that wants to display a combo box containing priorities for a single Todo such as High, Medium, Low. The form needs to know the primary key or id which is the enum value in this instance and the value should be the readable formatted value the combo box should display.
If you wish to customize the json response in 1 place only such as a single endpoint then I found this useful. The secret sauce is using the value object PriorityValue to allow you to rename the json field through #Relation.
public enum Priority {
HIGH("High"),
NORMAL("Normal"),
LOW("Low");
private final String description;
Priority(String description) {
this.description = description;
}
public String getDescription() {
return description;
}
public static List<Priority> orderedValues = new ArrayList<>();
static {
orderedValues.addAll(Arrays.asList(Priority.values()));
}
}
#RepositoryRestController
#RequestMapping(value="/")
public class PriorityController {
#Relation(collectionRelation = "priorities")
#JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY)
private class PriorityValue {
private String id;
private String value;
public PriorityValue(String id,
String value) {
this.id = id;
this.value = value;
}
}
#GetMapping(value = "/api/priorities", produces = MediaTypes.HAL_JSON_VALUE)
public ResponseEntity<Resources<PriorityValue>> getPriorities() {
List<PriorityValue> priorities = Priority.orderedValues.stream()
.map(p -> new PriorityValue(p.name(), p.getDescription()))
.collect(Collectors.toList());
Resources<PriorityValue> resources = new Resources<>(priorities);
resources.add(linkTo(methodOn(PriorityController.class).getPriorities()).withSelfRel());
return ResponseEntity.ok(resources);
}
}
Another approach is to use a custom JsonSerializer. The only issue using this is everywhere a Priority enum is serialized you will end up using this format which may not be what you want.
#JsonSerialize(using = PrioritySerializer.class)
#Relation(collectionRelation = "priorities")
public enum Priority {
HIGH("High"),
NORMAL("Normal"),
LOW("Low");
private final String description;
Priority(String description) {
this.description = description;
}
public String getDescription() {
return description;
}
public static List<Priority> orderedValues = new ArrayList<>();
static {
orderedValues.addAll(Arrays.asList(Priority.values()));
}
}
#RepositoryRestController
#RequestMapping(value="/api")
public class PriorityController {
#GetMapping(value = "/priorities", produces = MediaTypes.HAL_JSON_VALUE)
public ResponseEntity<Resources<Priority>> getPriorities() {
Resources<Priority> resources = new Resources<>(Priority.orderedValues);
resources.add(linkTo(methodOn(PriorityController.class).getPriorities()).withSelfRel());
return ResponseEntity.ok(resources);
}
}
public class PrioritySerializer extends JsonSerializer<Priority> {
#Override
public void serialize(Priority priority,
JsonGenerator generator,
SerializerProvider serializerProvider)
throws IOException, JsonProcessingException {
generator.writeStartObject();
generator.writeFieldName("id");
generator.writeString(priority.name());
generator.writeFieldName("value");
generator.writeString(priority.getDescription());
generator.writeEndObject();
}
}
The final json response from http://localhost:8080/api/priorities
{
"_embedded": {
"priorities": [
{
"id": "HIGH",
"value": "High"
},
{
"id": "NORMAL",
"value": "Normal"
},
{
"id": "LOW",
"value": "Low"
}
]
},
"_links": {
"self": {
"href": "http://localhost:8080/api/priorities"
}
}
}

where microservices code in https://dzone.com/articles/spring-boot-creating project ?

These days I'm hearing a lot about microservices and wondering to create POC (Proof of Concept) in order to be get applied in my project which will begin from scratched. I read a lots of blog about the mocroservices and found this link : https://dzone.com/articles/spring-boot-creating. I was able to successfully run the code mentioned in the link. But I feels that its a Simple Spring Boot REST example, I am not sure what is the role of microservices in this example ? I'd like to understand this from technical point of view now as I theoretically understand what it is. Please guide.
Please see code below for reference:
curl -vvv "http://localhost:8080/order?idCustomer=2&idProduct=3&amount=4"
Trying 127.0.0.1...
Connected to localhost (127.0.0.1) port 8080 (#0)
> GET /order?idCustomer=2&idProduct=3&amount=4 HTTP/1.1
> Host: localhost:8080 > User-Agent: curl/7.46.0
> Accept: / > < HTTP/1.1 200 < Content-Type: application/json < Content-Length: 173
< Date: Fri, 09 Sep 2016 07:22:02 GMT
< {"id":1,"amount":4,"orderDate":1473405722862,"customer":{"id":2,"name":"Customer 2","email":"Customer2#gmail.com"},"product":{"id":3,"sku":"abcd3","description":"Product3"}}* Connection #0 to host localhost left intact
Application.java
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
ApplicationConfig.java
#Configuration
public class ApplicationConfig {
#Named
static class JerseyConfig extends ResourceConfig {
public JerseyConfig() {
this.packages("br.com.alexandreesl.handson.rest");
}
}
#Bean
public RestTemplate restTemplate() {
RestTemplate restTemplate = new RestTemplate();
return restTemplate;
}
}
Customer.java
public class Customer {
private long id;
private String name;
private String email;
// setters and getters
}
CustomerRest.java
#Named
#Path("/customer")
public class CustomerRest {
private static List<Customer> customers = new ArrayList<Customer>();
static {
Customer customer1 = new Customer();
customer1.setId(1);
customer1.setName("Customer 1");
customer1.setEmail("customer1#gmail.com");
Customer customer2 = new Customer();
customer2.setId(2);
customer2.setName("Customer 2");
customer2.setEmail("Customer2#gmail.com");
Customer customer3 = new Customer();
customer3.setId(3);
customer3.setName("Customer 3");
customer3.setEmail("Customer3#gmail.com");
Customer customer4 = new Customer();
customer4.setId(4);
customer4.setName("Customer 4");
customer4.setEmail("Customer4#gmail.com");
Customer customer5 = new Customer();
customer5.setId(5);
customer5.setName("Customer 5");
customer5.setEmail("Customer5#gmail.com");
customers.add(customer1);
customers.add(customer2);
customers.add(customer3);
customers.add(customer4);
customers.add(customer5);
}
#GET
#Produces(MediaType.APPLICATION_JSON)
public List<Customer> getCustomers() {
return customers;
}
#GET
#Path("/getCustomer")
#Produces(MediaType.APPLICATION_JSON)
public Customer getCustomer(#QueryParam("id") long id) {
Customer cli = null;
for (Customer c : customers) {
if (c.getId() == id)
cli = c;
}
return cli;
}
}
Order.java
public class Order {
private long id;
private long amount;
private Date orderDate;
private Customer customer;
private Product product;
// setters and getters
}
OrderRest.java
#Named
#Path("/")
public class OrderRest {
private long id = 1;
#Inject
private RestTemplate restTemplate;
#GET
#Path("order")
#Produces(MediaType.APPLICATION_JSON)
public Order submitOrder(#QueryParam("idCustomer") long idCustomer,
#QueryParam("idProduct") long idProduct,
#QueryParam("amount") long amount) {
Customer customer = restTemplate.getForObject("http://localhost:8080/customer/getCustomer?id={id}", Customer.class, idCustomer);
Product product = restTemplate.getForObject("http://localhost:8080/product/getProduct?id={id}", Product.class,idProduct);
Order order = new Order();
order.setCustomer(customer);
order.setProduct(product);
order.setId(id);
order.setAmount(amount);
order.setOrderDate(new Date());
id++;
return order;
}
}
Product.java
public class Product {
private long id;
private String sku;
private String description;
// setters and getters
}
ProductRest.java
#Named
#Path("/product")
public class ProductRest {
private static List<Product> products = new ArrayList<Product>();
static {
Product product1 = new Product();
product1.setId(1);
product1.setSku("abcd1");
product1.setDescription("Product1");
Product product2 = new Product();
product2.setId(2);
product2.setSku("abcd2");
product2.setDescription("Product2");
Product product3 = new Product();
product3.setId(3);
product3.setSku("abcd3");
product3.setDescription("Product3");
Product product4 = new Product();
product4.setId(4);
product4.setSku("abcd4");
product4.setDescription("Product4");
products.add(product1);
products.add(product2);
products.add(product3);
products.add(product4);
}
#GET
#Produces(MediaType.APPLICATION_JSON)
public List<Product> getProducts() {
return products;
}
#GET
#Path("/getProduct")
#Produces(MediaType.APPLICATION_JSON)
public Product getProduct(#QueryParam("id") long id) {
Product prod = null;
for (Product p : products) {
if (p.getId() == id)
prod = p;
}
return prod;
}
}

Resources