Home > Net >  Java ArrayList of type Interface
Java ArrayList of type Interface

Time:05-18

I have two java endpoints in spring boot like this:

@PostMapping(path="/my-import-1")
@ResponseStatus(HttpStatus.OK)
public String myImport1(@Valid @RequestBody ParameterDto1 params) {
    return this.serviceImpl.import(params);
}

and

@PostMapping(path="/my-import-2")
@ResponseStatus(HttpStatus.OK)
public String myImport2(@Valid @RequestBody ParameterDto2 params) {
    return this.serviceImpl.import(params);
}

Both use the same service for importing, but have some differences in their parameters.

I created the service's import method like this

@Override
public String import(ParameterInterface params) throws Exception {
   ...
}

and the ParameterInterface like this

public interface ImportMetaData {
    public default ArrayList<FileInterface> getFiles() {
        return null;
    }
    public void setFiles(ArrayList<FileInterface> files);
}

Implementing this interface I created two ParameterDto classes (ParameterDto1 and ParameterDto2). The IDE shows everything is correct, also the start of my service works, but as soon as I send a request to one of the endpoints, I get the following error:

Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.http.converter.HttpMessageConversionException: Type definition error: [simple type, class com.beo.services.myImportService.rest.domain.dto.metadata.interfaces.ParameterInerface]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of com.beo.services.myImportService.rest.domain.dto.metadata.interfaces.ParameterInerface (no Creators, like default constructor, exist): abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information at [Source: (PushbackInputStream); line: 3, column: 5] (through reference chain: com.beo.services.myImportService.rest.domain.dto.metadata.ParameterDto["files"]->java.util.ArrayList[0])] with root cause

Can I any how create such an ArrayList from an interface and get these two endpoints running? Or is there another solution?

CodePudding user response:

The issue is with the ParameterDto1 and ParameterDto2. Jackson library requires a default, no-args constructor or a constructor with parameters annotated with @JsonProperty("field_name"), otherwise it cannot convert your message.

Solution:

Add a no-args constructor to ParameterDto1 and ParameterDto2 or annotate the constructor parameters with @JsonProperty("field_name")

CodePudding user response:

im guessing here because you didnt share the implementation of ParameterDto1 or ParameterDto2 - and for some reason your interface is called ImportMetaData where according to the exception, your explanation and other files it should be ParameterInterface.

the problem is that getFiles/setFiles is considered as a property by jackson , its type is an interface and you are not sending any type information.

in general assuming ParameterDto1 and ParameterDto2are using a concreate implementation of FileInterface you could just change your interface methods getFiles/setFiles so they are using generics parameter and in each implementation set the concreate type for FileInterface you are using , this will allow jackson to understand the concreate type for FileInterface .

incase ParameterDto1 and ParameterDto2 are not using a concreate implementation of FileInterface you should add @JsonTypeInfo or @JsonSubTypes (see https://www.baeldung.com/jackson-annotations section 5 for more info) - note that the client calling the api should also specify the actual type in the json-type field

Suggested implementation

public interface ParameterInterface {
@JsonIgnore
public List<FileInterface> getParameters() default { return null;}
.....
}

public class ParameterDto1 implements ParameterInterface {
private List<FileImpl1> files;
public List<FileImpl1> getFiles(){return files;}
public void setFiles(List<FileImpl1> files){this.files=files;}
....
}



public class ParameterDto2 implements ParameterInterface {
private List<FileImpl2> files;
public List<FileImpl2> getFiles(){return files;}
public void setFiles(List<FileImpl2> files){this.files=files;}
...
}


public class FileImpl1 implements FileInterface{

...
}

public class FileImpl2 implements FileInterface{

...
}
  • Related