BAEL-3324 | Using JSON Patch in Spring REST APIs

This commit is contained in:
ramprasad.devarakonda@gmail.com
2020-02-08 23:58:31 +00:00
parent 8dd58252de
commit 9da15e9d94
13 changed files with 534 additions and 0 deletions
@@ -0,0 +1,12 @@
package com.baeldung;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class CustomerSpringBootRestApplication {
public static void main(String[] args) {
SpringApplication.run(CustomerSpringBootRestApplication.class, args);
}
}
@@ -0,0 +1,79 @@
package com.baeldung.model;
import java.util.List;
import java.util.Map;
import java.util.Objects;
public class Customer {
private String id;
private String telephone;
private List<String> favorites;
private Map<String, Boolean> communicationPreferences;
public Customer() {
}
public Customer(String id, String telephone, List<String> favorites, Map<String, Boolean> communicationPreferences) {
this(telephone, favorites, communicationPreferences);
this.id = id;
}
public Customer(String telephone, List<String> favorites, Map<String, Boolean> communicationPreferences) {
this.telephone = telephone;
this.favorites = favorites;
this.communicationPreferences = communicationPreferences;
}
public static Customer fromCustomer(Customer customer) {
return new Customer(customer.getId(), customer.getTelephone(), customer.getFavorites(), customer.getCommunicationPreferences());
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getTelephone() {
return telephone;
}
public void setTelephone(String telephone) {
this.telephone = telephone;
}
public Map<String, Boolean> getCommunicationPreferences() {
return communicationPreferences;
}
public void setCommunicationPreferences(Map<String, Boolean> communicationPreferences) {
this.communicationPreferences = communicationPreferences;
}
public List<String> getFavorites() {
return favorites;
}
public void setFavorites(List<String> favorites) {
this.favorites = favorites;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof Customer)) {
return false;
}
Customer customer = (Customer) o;
return Objects.equals(id, customer.id);
}
@Override
public int hashCode() {
return Objects.hash(id);
}
}
@@ -0,0 +1,6 @@
package com.baeldung.service;
public interface CustomerIdGenerator {
int generateNextId();
}
@@ -0,0 +1,14 @@
package com.baeldung.service;
import com.baeldung.model.Customer;
import java.util.Optional;
public interface CustomerService {
Customer createCustomer(Customer customer);
Optional<Customer> findCustomer(String id);
void updateCustomer(Customer customer);
}
@@ -0,0 +1,17 @@
package com.baeldung.service.impl;
import com.baeldung.service.CustomerIdGenerator;
import org.springframework.stereotype.Component;
import java.util.concurrent.atomic.AtomicInteger;
@Component
public class CustomerIdGeneratorImpl implements CustomerIdGenerator {
private static final AtomicInteger SEQUENCE = new AtomicInteger();
@Override
public int generateNextId() {
return SEQUENCE.incrementAndGet();
}
}
@@ -0,0 +1,42 @@
package com.baeldung.service.impl;
import com.baeldung.model.Customer;
import com.baeldung.service.CustomerIdGenerator;
import com.baeldung.service.CustomerService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
@Service
public class CustomerServiceImpl implements CustomerService {
private CustomerIdGenerator customerIdGenerator;
private List<Customer> customers = new ArrayList<>();
@Autowired
public CustomerServiceImpl(CustomerIdGenerator customerIdGenerator) {
this.customerIdGenerator = customerIdGenerator;
}
@Override
public Customer createCustomer(Customer customer) {
customer.setId(Integer.toString(customerIdGenerator.generateNextId()));
customers.add(customer);
return customer;
}
@Override
public Optional<Customer> findCustomer(String id) {
return customers.stream()
.filter(customer -> customer.getId().equals(id))
.findFirst();
}
@Override
public void updateCustomer(Customer customer) {
customers.set(customers.indexOf(customer), customer);
}
}
@@ -0,0 +1,69 @@
package com.baeldung.web.controller;
import com.baeldung.model.Customer;
import com.baeldung.service.CustomerService;
import com.baeldung.web.exception.CustomerNotFoundException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.fge.jsonpatch.JsonPatch;
import com.github.fge.jsonpatch.JsonPatchException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
import java.net.URI;
import javax.validation.Valid;
@RestController
@RequestMapping(value = "/customers")
public class CustomerRestController {
private CustomerService customerService;
private ObjectMapper objectMapper = new ObjectMapper();
@Autowired
public CustomerRestController(CustomerService customerService) {
this.customerService = customerService;
}
@PostMapping(consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Customer> createCustomer(@RequestBody Customer customer) {
Customer customerCreated = customerService.createCustomer(customer);
URI location = ServletUriComponentsBuilder.fromCurrentRequest()
.path("/{id}")
.buildAndExpand(customerCreated.getId())
.toUri();
return ResponseEntity.created(location).build();
}
@PatchMapping(path = "/{id}", consumes = "application/json-patch+json")
public ResponseEntity<Customer> updateCustomer(@PathVariable String id,
@RequestBody JsonPatch patch) {
try {
Customer customer = customerService.findCustomer(id).orElseThrow(CustomerNotFoundException::new);
Customer customerPatched = applyPatchToCustomer(patch, customer);
customerService.updateCustomer(customerPatched);
return ResponseEntity.ok(customerPatched);
} catch (CustomerNotFoundException e) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
} catch (JsonPatchException | JsonProcessingException e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
}
private Customer applyPatchToCustomer(JsonPatch patch, Customer targetCustomer) throws JsonPatchException, JsonProcessingException {
JsonNode patched = patch.apply(objectMapper.convertValue(targetCustomer, JsonNode.class));
return objectMapper.treeToValue(patched, Customer.class);
}
}
@@ -0,0 +1,5 @@
package com.baeldung.web.exception;
public class CustomerNotFoundException extends RuntimeException {
}