简体   繁体   English

接口类型的 Java ArrayList

[英]Java ArrayList of type Interface

I have two java endpoints in spring boot like this:我在 Spring Boot 中有两个 Java 端点,如下所示:

@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和像这样的ParameterInterface

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).为了实现这个接口,我创建了两个 ParameterDto 类(ParameterDto1 和 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: IDE 显示一切正确,我的服务也开始工作,但只要我向其中一个端点发送请求,就会收到以下错误:

Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; Servlet.service() 用于路径 [] 上下文中的 servlet [dispatcherServlet] 引发异常 [请求处理失败; nested exception is org.springframework.http.converter.HttpMessageConversionException: Type definition error: [simple type, class com.beo.services.myImportService.rest.domain.dto.metadata.interfaces.ParameterInerface];嵌套异常是org.springframework.http.converter.HttpMessageConversionException:类型定义错误:[简单类型,类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);嵌套异常是 com.fasterxml.jackson.databind.exc.InvalidDefinitionException:无法构造com.beo.services.myImportService.rest.domain.dto.metadata.interfaces.ParameterInerface的实例(没有创建者,如默认构造函数,存在):抽象类型要么需要映射到具体类型,具有自定义反序列化器,要么在 [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行:3,列:5](通过参考链:com.beo.services.myImportService.rest.domain.dto.metadata.ParameterDto["files"]->java.util.ArrayList[0])] 有根本原因

Can I any how create such an ArrayList from an interface and get these two endpoints running?我可以如何从接口创建这样的 ArrayList 并让这两个端点运行吗? Or is there another solution?还是有其他解决方案?

The issue is with the ParameterDto1 and ParameterDto2.问题在于 ParameterDto1 和 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. Jackson 库需要一个默认的无参数构造函数或带有带有@JsonProperty("field_name")注释的参数的构造函数,否则它无法转换您的消息。

Solution:解决方案:

Add a no-args constructor to ParameterDto1 and ParameterDto2 or annotate the constructor parameters with @JsonProperty("field_name")向 ParameterDto1 和 ParameterDto2 添加无参数构造函数,或使用@JsonProperty("field_name")注释构造函数参数

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 .我在这里猜测是因为您没有共享ParameterDto1ParameterDto2的实现-由于某种原因,您的接口被称为ImportMetaData根据异常,您的解释和其他文件应该是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.问题是 getFiles/setFiles 被 jackson 视为一个属性,它的类型是一个接口,您没有发送任何类型信息。

in general assuming ParameterDto1 and ParameterDto2 are 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 .一般来说,假设ParameterDto1ParameterDto2正在使用 FileInterface 的FileInterface实现,您可以只更改接口方法getFiles / setFiles以便它们使用泛型参数,并在每个实现中设置您正在使用的FileInterface的 concreate 类型,这将使​​杰克逊能够理解为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如果ParameterDto1ParameterDto2没有使用 FileInterface 的FileInterface实现,您应该添加@JsonTypeInfo@JsonSubTypes (有关更多信息,请参阅https://www.baeldung.com/jackson-annotations第 5 节) - 请注意,调用 api 的客户端应该还要在 json-type 字段中指定实际类型

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{

...
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM