How can obtain a Link when in the controller the mappings of the rest endpoints are defined by a SPEL? - spring-hateoas

I am using Spring Hateoas 1.5.2 and I have a scenario where I cannot produce a Link.
#RestController
#RequestMapping("${unexisting.property.controller:/spel-defined-url}")
public class SpelDefinedController {
#AllArgsConstructor
#Data
private static class ExampleDto {
private String test;
}
#GetMapping(value = "${unexisting.property.controller.documentation:/another-spel-persons/{id}}", produces = "application/json")
public EntityModel<ExampleDto> findOne(#PathVariable Long id) {
// Creation of the self link"self" link, i.e. this method.
Link findOneLink = linkTo(methodOn(SpelDefinedController.class).findOne(id)).withSelfRel();
// We return
return EntityModel.of(new ExampleDto("test"), findOneLink);
}
}
The line of code that fails is this one
Link findOneLink = linkTo(methodOn(SpelDefinedController.class).findOne(id)).withSelfRel();
I think the issue comes with the fact that I am using SPEL inside the #Controller or the #GetMapping and these SPELs are not resolved by the linkTo.
Or I am doing something wrong. Any help to understand is appreciated.

Related

How to access nested Json Object Value into JPA Entity Class

I have a payload like this
{
"eventId":"ep9_0579af51",
"eventTime":"5/11/2022 5:50:58 PM",
"eventType":"UpdateTransaction",
"meta":{
"userId":"vkp",
"resourceType":"Transaction/DataDocs"
}
}
I need to map this json fields into a single entity class .
#PostMapping(path = "/id", consumes = "application/json")
public ResponseEntity<ImportTrans> import(#RequestBody ImportTrans importTrans) {
return ResponseEntity.of(Optional.ofNullable(repository.save(importTrans););
}
#Table(name = "IMPORT_TRANS")
#Entity
public class ImportTrans implements Serializable {
#Id
private Long processId;// AutoGenerator
private String eventId;
private Date eventTime;
private String eventType;
private String userId; // I dont want create new class for meta . Is there any way i
//can access meta.userId in ImportTrans class.
private String resourceType;
}
How can I access data from meta from ImportTrans without creating a separate class for it?
You should modify your request body before reaching the controller.
"You must consider the application performance factors on your own
before implementation"
Option 1. Using RequestBodyAdvice.
Option 2. Using Spring HandlerInterceptor.
Option 3. Use AOP
Option 4. Using HTTP Filter.
The below solution only works if you are using a separate DTO class.
private Map<String, String> meta = new HashMap<>();
String userID = importTrans.getMeta().get("userId");
I hope the above pieces of information answered your question.

RestController Response with JSON vs. Controller Response with Model

I am studying sprint boot these days.And i'm trying develop a e-bank project with Spring boot. I can't understand why to could get direct response with JSON of restcontroller. I could use Model object with end-point that return of controller method. And i could process that model object to purpose on front-end side. But i don't know how to procces if i get response as JSON directly. If i could not, why could we return JSON directly? Can you explain these for me ?
You can take a look my restController and controller classes at my practice project
RestController response with JSON
#RequiredArgsConstructor(onConstructor = #__(#Autowired))
#RestController
#RequestMapping("/rest/customer")
public class CustomerRestController {
private final CustomerService customerService;
#GetMapping("/{id}")
public Customer getCustomer(#PathVariable Long id) {
Optional<Customer> customer = customerService.getCustomer(id);
if(customer.isEmpty()) {
return null;
}
return customerService.getCustomer(id).get();
}
}
Controller Response with Model object
#Slf4j
#Controller
#RequiredArgsConstructor
#RequestMapping("/customer")
public class CustomerController {
private final CustomerService customerService;
#GetMapping("/{id}")
public String getCustomer(Model model, #PathVariable("id") Long id) {
Optional<Customer> customer = customerService.getCustomer(id);
if(customer.isEmpty())
log.error("Customer with id {} not found", id);
model.addAttribute("customer", customer.get());
return "customers/customer-profile";
}
}
I hope to explain myself and my question. Sorry about my english. Thank you :)

how to send delete request without knowing the id in json?

for example
if i have used findByEmail my url will look something like this
http://localhost:8080/api/carts/search/findByEmail?email=helloworld#gmail.com
how will the URL for delete request look if i have deleteByEmail in JPA repository
this is how my JPA looks like
public interface CartRepository extends JpaRepository<Cart, Integer> {
#Transactional
#RestResource(exported = true)
List<Cart> deleteByEmail(String email);
}
You can have a rest API as http://localhost:8080/api/carts/email/{emailId} with emailId in PathVariable HttpMethod as DELETE. Inside the service method, you search by emailId and then Delete it using the ID.
You need to create a controller method with the appropriate mapping. You can define any URL you want, I used /api/carts/{email}. Make sure to send a HTTP DELETE request.
#RestController
public class CartController {
private final CartRepository cartRepository;
#Autowired
public CartController (CartRepository cartRepository) {
this.cartRepository = cartRepository;
}
#DeleteMapping("/api/carts/{email}")
public void deleteCart(#PathVariable String email) {
cartRepository.deleteByEmail(email);
}
}
If you prefer to solve this with a request param, change the deleteCart method as shown below:
#DeleteMapping("/api/carts")
public void deleteCart(#RequestParam String email) {
cartRepository.deleteByEmail(email);
}

spring boot: change print console to json rest

Actually, my project in Spring send values from the database via console, like this:
Console image, but I want to send this values via JSON like a rest API, but I don't know how to change that.
{
"depositarios": {
"correo": "correo",
"nombre": "nombre",
"numTel": "numTel",
"pApellido": "pApellido",
"SApellido": "sAellido"
}
}
this is my main class:
#SpringBootApplication
#ComponentScan("com.abner.springpostgresql.service.impl, com.abner.springpostgresql.dao.imp")
public class SpringPostgresqlApplication {
public static void main(String[] args) {
ApplicationContext context= SpringApplication.run(SpringPostgresqlApplication.class, args);
depoService depoService =context.getBean(depoService.class);
depoService.loadAllDepo();
}
}
this is my entired project source https://github.com/abnercoronado/restpostgresql
You have to create a RestController using the #RestController annotation like this:
#RestController
public class MyRestController {
#RequestMapping(value = "/personas", method = RequestMethod.GET)
public List<Persona> listaPersonas() {
// This is just a sample. Here you could bring your data form your db
List<Persona> lista = new ArrayList<Persona>();
Persona p = new Persona();
p.setNombre("angel");
p.setEdad(20);
lista.add(p);
return lista;
}
}
The value of the #RequestMapping annotation ("/personas" in this example) will be the endpoint. So when you access to the endpoint http://localhost:8080/personas (asuming that your app is running on http://localhost:8080) then you will get your data as json.
Here is an example of how to do it.
Here is another example (en espaƱol) that could help you.
You can use ObjectMapper to convert your pojo or object to JSON String and send where ever you wanted using thier API or anything.
Or you can create Rest Method and Access the API would return you the Json Value.
#RestController
public class MyRestController {
#RequestMapping(value = "/depo", method = RequestMethod.GET)
public List<?> getDepo() {
ApplicationContext context= SpringApplication.run(SpringPostgresqlApplication.class, args);
depoService depoService =context.getBean(depoService.class);
List<?> lista = depoService.loadAllDepo();
return lista;
}
Another way of doing.
#RestController
public class MyRestController {
#RequestMapping(value = "/depo", method = RequestMethod.GET)
public List<Depo> getDepo() {
ApplicationContext context= SpringApplication.run(SpringPostgresqlApplication.class, args);
depoService depoService =context.getBean(depoService.class);
List<Depo> lista = depoService.loadAllDepo();
return lista;
}
Once you start your server, you can run this by doing localhost:8080/depo. you can also return XML.

JAX-RS - JSON List to Object with JaxB

I am using JAX-RS (CXF) with JaxB and Jackson to provide a REST-API.
Unfortunately, none of the found results helps me with following (simple) problem:
I implemented following method:
#POST
#Path(ApiStatics.ARMY_CREATE_ARMY)
public com.empires.web.dto.Army createArmy(#FormParam("locationid") long locationId, #FormParam("name") String name, #FormParam("troops") ArmyTroops troops) {
and here are is my model class:
#XmlRootElement
#XmlSeeAlso(ArmyTroop.class)
public class ArmyTroops {
public ArmyTroops() {
}
public ArmyTroops(List<ArmyTroop> troops) {
this.troops = troops;
}
#XmlElement(name = "troops")
private List<ArmyTroop> troops = new ArrayList<ArmyTroop>();
public List<ArmyTroop> getTroops() {
return troops;
}
public void setTroops(List<ArmyTroop> troops) {
this.troops = troops;
}
}
ArmyTroop
#XmlRootElement(name = "troops")
public class ArmyTroop {
#XmlElement
private long troopId;
#XmlElement
private String amount;
public long getTroopId() {
return troopId;
}
public void setTroopId(long troopId) {
this.troopId = troopId;
}
public String getAmount() {
return amount;
}
public void setAmount(String amount) {
this.amount = amount;
}
}
My json that i send looks like this:
locationid 1
name asdasd
troops {"troops":[{"troopId":4,"amount":"5"},{"troopId":6,"amount":"5"}]}
Unfortunately, the object gets not transformed. Instead I receive this error:
InjectionUtils #reportServerError - Parameter Class com.empires.web.dto.in.ArmyTroops has no constructor with single String parameter, static valueOf(String) or fromString(String) methods
If I provide the constructor with a single string parameter, I get passed the whole json string for "troops" as mentioned above.
Any ideas why JaxB does not work at this point?
You are passing all your parameters with #Form annotation.
But the Form part of the http message must be an xml data structure.
Your 3 parameters don't have a main xml datastructure so it wont work.
In short, form params are send as body.
Cxf use the MultivaluedMap to send params (cxf have an xml model for this structure).
As you can see it is not fit for parameters that can't be trivally serialized.
Here me solution would be to drop the #FormParam to avoid the problem:
1) Use #PathParam #CookieParam to send yours first 2 parameters, and the 'no tag' (body) only for the army compositions.
2) Define an uber object that take all parameters and can be serialized as xml datastructure and use the 'no tag' (body) sending.
3) Use soap, with cxf it is really easy to gets both Rest and Soap.