1

I'm trying to create a communication between two services with Spring Boot, and I'm failing to return a custom object from a POST.

I have tried something like

1st service:

@RestController
@RequestMapping("/broker")
class HostController{
    @PostMapping(value = "/bid")
    public Bid bid(@RequestBody Auction auction){
        return new Bid(new URI("http://url:8080"));
    }
}

2nd service:

ResponseEntity<Bid> response = rest.postForEntity(hostURL + "/bid", auction, Bid.class);
response.getBody();

The problem is I get an error message saying "cannot deserialize from Object value" for the Bid class, which makes me think the Auction is being sent but the Bid isn't sent back.

I'm also not sure how the serialization happens for the auction, as I only put the "@RequestBody" and it started working. The Auction class even has a Bid object inside, but that doesn't seem to be a problem.

class Bid{
    private URI host;
    
    public Bid(URI host){ this.host = host; }

    public URI getHost() { return host; }
}

class Auction{
    URI host;

    private Bid winner; //Not defined when the problem happens

    public Auction(URI host){ this.host = host; }
    
    public URI getHost(){ return host; }
}

The full stack trace is gigantic, but the part I think is relevant is this:

com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `com.gustavovbs.microservicesoffloading.Bid` (no Creators, like default constructor, exist): cannot deserialize from Object value (no delegate- or property-based Creator)\n at [Source: (PushbackInputStream); line: 1, column: 2]\n\tat
 
com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:67)\n\tat
 com.fasterxml.jackson.databind.DeserializationContext.reportBadDefinition(DeserializationContext.java:1764)\n\tat
 com.fasterxml.jackson.databind.DatabindContext.reportBadDefinition(DatabindContext.java:400)\n\tat

com.fasterxml.jackson.databind.DeserializationContext.handleMissingInstantiator(DeserializationContext.java:1209)\n\tat
 com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1415)\n\tat
 com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:362)\n\tat
 com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:195)\n\tat
 com.fasterxml.jackson.databind.deser.DefaultDeserializationContext.readRootValue(DefaultDeserializationContext.java:322)\n\tat
 com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4593)\n\tat
 com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3601)\n\tat
 org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:378)\n\t... 63 more\n","message":"Type definition error: [simple type, class com.gustavovbs.microservicesoffloading.Bid]; 

nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `com.gustavovbs.microservicesoffloading.Bid` (no Creators, like default constructor, exist): cannot deserialize from Object value (no delegate- or property-based Creator)\n at [Source: (PushbackInputStream); line: 1, column: 2]","path":"/broker/broadcast"}"

  • 1
    Please [edit] the question, add the whole `@Controller` and the full stack trace. If possible, please provide a [MRE] (e.g. as git repository). – Turing85 Nov 22 '21 at 19:05
  • 3
    Make sure `Bid` is a Serializable class, and that it has the appropriate getters and setters – Razvan Fulea Nov 22 '21 at 19:06
  • Unclear what serialization you're expecting. YAML? JSON? XML? Binary? – OneCricketeer Nov 22 '21 at 19:12
  • 1
    @RazvanFulea the class does not have to `implements Serializable`. If the getters are missing, we should at least receive an empty JSON, but not an exception. – Turing85 Nov 22 '21 at 19:13
  • I edited the question with a bit more of the code. I don't fully understand what I have to automatically serialize the objects the right way, but it isn't a lot different from the Auction Class. – Gustavo Vilas Boas Nov 22 '21 at 19:51
  • You seem to be missing a default constructor on `Bid` class – Razvan Fulea Nov 22 '21 at 20:03
  • Yes, default constructor is missing. See also https://stackoverflow.com/a/52304504/1938574 which is the first thing Google finds for the com.fasterxml.jackson.databind.DeserializationContext.handleMissingInstantiator in your stack trace – Gregor Ophey Nov 22 '21 at 20:07
  • Then again, without a default constructor your controller should not compile, since you call the Bid default constructor in line 6 (counting the lines in your first code sample) – Gregor Ophey Nov 22 '21 at 20:12
  • If I use a default constructor the host property will still be sent? I understood from the error message that I needed either a default constructor or an object that could be serialized, not necessarily both – Gustavo Vilas Boas Nov 22 '21 at 20:14
  • Oh, I call the URI constructor in line 6, I will edit the question, my bad. – Gustavo Vilas Boas Nov 22 '21 at 20:16
  • Note error ```Bid` (no Creators, like default constructor, exist``` – java dev Nov 22 '21 at 20:26
  • I managed to make it work with the default constructor and some specific bug fixing, thanks all! I still do not fully understand why the need for the default constructor for the Bid class though. The Auction class does not have a default constructor but I don't have this problem with it. Does it have something to do with being used as a RequestBody vs a ResponseBody or is it how I created the class? You were all a great help nevertheless, thank you! – Gustavo Vilas Boas Nov 22 '21 at 20:40
  • @GustavoVilasBoas, turn your comment into an answer with all the details of how you solved your issue and then accept it so that others can benefit from it. Thanks! – João Dias Nov 23 '21 at 00:46
  • Ok, have to wait 2 days for approving though. – Gustavo Vilas Boas Nov 23 '21 at 01:16

2 Answers2

2

When you transfer some stuff, make sure its serializable and also dont forget to add no arg constructor. This should work.

   class Bid implements Serializable {
    
    private URI host;

    public Bid();

    public URI getHost() {
        return host;
    }

    public void setHost(URI host) {
        this.host = host;
    }
}
0

I managed to make it work just by adding the default constructor to the Bid class, as discussed in the comments.

class Bid{
    private URI host;

    public Bid(){}
    
    public Bid(URI host){ this.host = host; }

    public URI getHost() { return host; }
}