0

I'm receiving an id (integer) and a executor (String) in my controller (Rest API). However, when looking at my database, I see that the string is being inserted into the database as an object. Example of database entry:

{
    "executor": "Pietje"
}

Controller:

@PostMapping(path = "/accept/{id}")
public String acceptAssignment(@Valid @PathVariable Integer id, @RequestBody String executor) {
    return assignmentService.acceptAssignment(id, executor);
}

Service implementation:

@Override
public String acceptAssignment(Integer id, String executor) {
    Assignment assignment = assignmentRespository.findById(id).orElse(null);
    
    assignment.setExecutor(String.valueOf(executor));
    
    AssignmentDTO assignmentDTO = assignmentConverter.convertEntityToDto(assignment);
    
    assignmentRespository.save(assignment);
    
    return assignmentDTO.getExecutor();
}

What am I doing wrong, and how can I fix it?

I could pass along the entire DTO instead of just the 'executor' value, but that doesn't seem efficient. As far as I know, the problem is not with the frontend but I could add the React code if necessary.

2 Answers 2

1

TL;DR - you're using a String containing a JSON-object as if it was an attribute of this JSON-object. The solution it to treat this JSON properly.

Note that you don't need to mess with desirialization manually, let the JSON-converter of the framework do its job.

All that you need is a simple POJO:

@Getter
@Setter
public class AssignmentExecutor {
    private String executor;
}

The above POJO can be automatically translated in & to the following of JSON without any effort from your side (owing to the magic of Spring):

{
    "executor": "Pietje"
}

It would be automatically parsed to the proper type by a Spring's message-converter, you only need to specify that you need an AssignmentExecutor instead of a plain String.

@PostMapping(path = "/accept/{id}")
public String acceptAssignment(@Valid @PathVariable Integer id,
                               @RequestBody AssignmentExecutor executor) {
    
    return assignmentService.acceptAssignment(id, executor);
}

Note

  • Introducing this new type would not require any changes in the Assignment, executor can still be represented as a String field.
  • By invoking orElse(null) on the optional result, you're creating a potential problem by depriving the possibility to get a meaningful exception if the data that corresponds to the given id was not found. In such a case, your current code would trigger a NullPointerException right on the next line. Instead, I would advise providing a suitable exception via Optional.orElseThrow().

A now again all that you need is to return an instance of AssignmentExecutor and it would be automatically converted into JSON:

@Override
public String acceptAssignment(Integer id, AssignmentExecutor executor) {
    Assignment assignment = assignmentRespository.findById(id)
        .orElseThrow(() -> new MyException("Assignment with id " + id + " was not found"));
    
    assignment.setExecutor(executor.getExecutor());
    assignmentRespository.save(assignment);
    
    return executor;
}
Sign up to request clarification or add additional context in comments.

Comments

0

You can use ObjectMapper to fetch the desired key-value from the @RequestBody String executor as:

Approach Here:

The @RequestBodythat you are getting from the API is in the object form and using ObjectMapper , it will be converted into a Map of attributes as in the API request and we can fetch the desired key-value pair.

ObjectMapper mapper = new ObjectMapper();
Map<String,Object> map = mapper.readValue(executor, new TypeReference<>() {});
String s = (String) map.get("executor");

Added in acceptAssignment method as:

 @Override
  public String acceptAssignment(Integer id, String executor) throws JsonProcessingException {

    ObjectMapper mapper = new ObjectMapper();
    Map<String,Object> requestMap = mapper.readValue(executor, new TypeReference<>() {});
    Assignment assignment = assignmentRespository.findById(id).orElse(null);
    assignment.setExecutor((String)requestMap.get("executor"));
    AssignmentDTO assignmentDTO = assignmentConverter.convertEntityToDto(assignment);
    assignmentRespository.save(assignment);

    return assignmentDTO.getExecutor();
  }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.