'HttpMessageNotWritableException: No converter for [...] with preset Content-Type 'null'] with OpenApi Spring generator

I am implementing the petstore API with openAPI in a (gradle) spring boot project. I generate a server with the openapi generator plugin and implement a simple request:

@Service
@RestController
public class PetApiController implements PetApi {

    @Override
    public ResponseEntity<Pet> getPetById(Long petId) {
        Pet p = new Pet();
        p.setId(0L);
        p.setName("fido");
        p.setPhotoUrls(new ArrayList<String>());
        p.setStatus(StatusEnum.AVAILABLE);
        p.setTags(new ArrayList<Tag>());
        Category c = new Category();
        c.setId(3L);
        c.setName("dummy category");
        p.setCategory(c);
        
        ResponseEntity<Pet> r = new ResponseEntity<Pet>(p, HttpStatus.OK);
        
        return r;
    }
}

The swagger-ui that I generate offers both xml and json queries for a request, but xml doesn't seem to work:

$ curl -X GET "http://localhost:8080/pet/1" -H  "accept: application/xml"; echo ""

$ curl -X GET "http://localhost:8080/pet/1" -H  "accept: application/json"; echo ""
{"id":0,"name":"fido","category":{"id":3,"name":"dummy category"},"photoUrls":[],"tags":[],"status":"available"}

I even get an error message:

2020-09-10 09:04:34.213  WARN 23958 --- [nio-8080-exec-1] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.http.converter.HttpMessageNotWritableException: No converter for [class com.petstore.server.model.Pet] with preset Content-Type 'null']

However I cannot catch this exception and print the whole context, it only happens after return r

There is already a question with my exact error message: Springboot HttpMessageNotWritableException: No converter for [...] with preset Content-Type 'null'] But I still think my context is different since I generate my POJOs so I have no controll over them and I shouldn't have this problem in the first place since the plugin should generate everything fittingly.



Solution 1:[1]

for me a problem was in lines:

responses:
        "200":
          description: default response
          content:
            '*/*' # <---- here
              schema:

instead of '*/*' it should be 'application/json'

Solution 2:[2]

You need to add support for xml format using the below dependency in your pom file:

<dependency>
    <groupId>com.fasterxml.jackson.dataformat</groupId>
    <artifactId>jackson-dataformat-xml</artifactId>
    <version>2.1.1</version>
</dependency>

Note : here version is the latest as per today.

Solution 3:[3]

According awnser by Peer, i have resolve my issue but it is different way. You need add "text/xml" to tell spring. Even though this limits your API to being JSON-based (which is fine for your needs), you’re welcome to set produces to an array of String for multiple content types. For example, to allow for XML output, you could add “text/html” to the produces attribute:

@RequestMapping(path = "your_path", produces = {"application/json", "text/xml"})

Solution 4:[4]

In my case, my class Pet didn't have a getter at all.

So I fixed the problem just by adding get methods for fields.

Solution 5:[5]

I renamed the types because types named Interface, Inner, and Outer<T> scramble my brain. Hopefully this makes the relationships between types easier to see.

interface IAnimal { }

class Dog : IAnimal { }

class PetStore<T> : IAnimal where T : IAnimal
{}

And when we simplify it, the question is why won't the compiler let us do this?

PetStore<IAnimal> casted = new PetStore<Dog>(); 

Every Dog is an IAnimal, so why can't we do this?

There's always something that the compiler is protecting us from. Sometimes it's hard to figure out what that something is.

It becomes clearer if we add a little bit to PetStore<T> and another class:

class PetStore<T> : IAnimal where T : IAnimal
{
    private List<T> _pets = new List<T>();

    public void Add(T foo)
    {
        _pets.Add(foo);
    }
}

class Cat : IAnimal { }

If we have an instance of PetStore<Dog> then the inner list contains items of types Dog. Every item we add to the list must be of type Dog.

If we could cast this as PetStore<IAnimal> then we could do this:

var dogStore = new PetStore<Dog>();
PetStore<IAnimal> animalStore = (PetStore<IAnimal>)dogStore;
animalStore.Add(new Cat())

Now we can see what the compiler is preventing. dogStore is a PetStore<Dog>. Every item in the _pets list must be a Dog.

But by casting the object as PetStore<IAnimal> we would make it possible to add a Cat to the list, because Cat is an IAnimal. That wouldn't make any sense. It's a List<Dog>, so how could we add something to the list that isn't a Dog?


Here's an even simpler version that illustrates the issue with less noise:

var dogs = new List<Dog>();
var animals = (List<IAnimal>)dogs; // this won't compile.
animals.Add(new Cat());

We may have tried to do this at some point. The compiler doesn't allow it for exactly the same reason. It would allow us to create a List<Dog> and then add something to it that's not a Dog.

We might reason that we would never try to add a Cat to the list because we know it's only supposed to contain dogs. But in that case why cast the List<Dog> as a List<IAnimal> in the first place?

Also, what if we have a method like this:

void DoSomethingWithListOfAnimals(List<IAnimal> animals)

If we could cast our List<Dog> as a List<IAnimal> then we could pass it as an argument to this method. The code in this method has no way of knowing that this list was only supposed to contain dogs. It just knows that it has a List<IAnimal>.

It's helpful if we can understand why the compiler won't let us do something. But for practical purposes the compiler is always right. If it won't let us do something there's a reason.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Alexey Stepanov
Solution 2 Coder17
Solution 3
Solution 4 Oleg Ushakov
Solution 5