java 无法解析类型变量“T”(具有类com.yaml.Example的上下文)

xzlaal3s  于 2023-02-02  发布在  Java
关注(0)|答案(1)|浏览(266)

我是一个java泛型的初学者,我尝试在类中使用泛型来解析我的user.yaml文件。当我尝试解析yaml文件时,我得到 * 类型变量'T'无法解析 * 不确定我哪里出错了。
最初这只是一个普通的类,然后我实现了泛型。

my yaml file

user:
    name: Test User
    age: 30
public interface IUser {
    String getName();
    IUser  setName(String name);

    Integer getAge();
    IUser setAge(Integer age);
}

public class User implements IUser{

    @JsonProperty("name")
    private String name;
    @JsonProperty("age")
    private Integer age;
    @JsonIgnore
    private Map<String, Object> additionalProperties = new HashMap<String, Object>();

    @JsonProperty("name")
    public String getName() {
        return name;
    }

    @JsonProperty("name")
    public User setName(String name) {
        this.name = name;
        return this;
    }

    @JsonProperty("age")
    public Integer getAge() {
        return age;
    }

    @JsonProperty("age")
    public User setAge(Integer age) {
        this.age = age;
        return this;
    }

    @JsonAnyGetter
    public Map<String, Object> getAdditionalProperties() {
        return this.additionalProperties;
    }

    @JsonAnySetter
    public void setAdditionalProperty(String name, Object value) {
        this.additionalProperties.put(name, value);
    }

    @Override
    public String toString() {
        return new ToStringBuilder(this).append("name", name).append("age", age).append("additionalProperties", additionalProperties).toString();
    }

    @Override
    public int hashCode() {
        return new HashCodeBuilder().append(additionalProperties).append(age).append(name).toHashCode();
    }

    @Override
    public boolean equals(Object other) {
        if (other == this) {
            return true;
        }
        if ((other instanceof User) == false) {
            return false;
        }
        User rhs = ((User) other);
        return new EqualsBuilder().append(additionalProperties, rhs.additionalProperties).append(age, rhs.age).append(name, rhs.name).isEquals();
    }
}
public interface IExample {
    <T extends IUser> T getUser();
    <T extends IUser> void setUser(T user);
}

public class Example implements IExample{

    @JsonProperty("user")
    private User user;
    @JsonIgnore
    private Map<String, Object> additionalProperties = new HashMap<String, Object>();

    @JsonProperty("user")
    public <T extends IUser> T getUser() {
        return (T) user;
    }

    @JsonProperty("user")
    public <T extends IUser> void setUser(T t) {
        this.user = (User)t;
    }

    @JsonAnyGetter
    public Map<String, Object> getAdditionalProperties() {
        return this.additionalProperties;
    }

    @JsonAnySetter
    public void setAdditionalProperty(String name, Object value) {
        this.additionalProperties.put(name, value);
    }

    @Override
    public String toString() {
        return new ToStringBuilder(this).append("user", user).append("additionalProperties", additionalProperties).toString();
    }

    @Override
    public int hashCode() {
        return new HashCodeBuilder().append(additionalProperties).append(user).toHashCode();
    }

    @Override
    public boolean equals(Object other) {
        if (other == this) {
            return true;
        }
        if ((other instanceof Example) == false) {
            return false;
        }
        Example rhs = ((Example) other);
        return new EqualsBuilder().append(additionalProperties, rhs.additionalProperties).append(user, rhs.user).isEquals();
    }
}
my main class where i'm trying to parse yaml object

public class ReadYaml {

    public void parse(){
        String path = "path/to/user.yaml";
        ObjectMapper mapper = new ObjectMapper(new YAMLFactory());

        try {
             IExample example = mapper.readValue(new File(path), Example.class);
             System.out.println(example.getUser().getName());
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    public static void main(String[] args){
      new ReadYaml().parse();
    }
}

我希望输出为:* 测试用户 ,但实际输出为 * com. fasterxml. jackson. databind. JsonMappingException:无法解析类型变量'T'(具有类com.yaml.Example的上下文)

更新

updated yaml file

user:
    name: Test User
    age: 30
address:
    line1: bangalore
    line2: karnataka
public interface IAddress {

    String getLine1();
    IAddress setLine1(String line1);

    String getLine2();
    IAddress setLine2(String line2);
}
public class Address implements IAddress {
    // code getters and setters
}
public interface IExample<T, U extends IUser & IAddress> {
    T getUser();
    void setUser(T user);

    U getAddress();
    void setAddress(U address);
}
public class Example<T, U extends IUser & IAddress> implements IExample<T, U>{
now i'm trying to parse yaml file.
public class ReadYaml {
.
.
.

TypeReference<Example<User, Address> typeReference = new TypeReference<Example<User, Address>() {
            };
IExample example = mapper.readValue(new File(path), typeReference);
System.out.println(example.getAddress.getLine1());

TypeReference<Example<User, Address> typeReference声明中出现错误:类型参数"Address"不在其界限内,应实现"IUser"

wfsdck30

wfsdck301#

由于java's type erasure,您的代码有2个问题;这要求Jackson知道在反序列化数据时要使用的所有具体类型。在泛型类型的情况下,它需要知道要使用的泛型类的界限(参数化类型的具体类)。Jackson通过类型引用被告知该界限;你需要提供的。那么你有两个问题:
1.据我所知,Jackson无法获知泛型方法的边界(这没有多大意义),因此,在Example中,属性userpublic <T extends IUser> void setUser(T t))代表了一个障碍,因为Jackson无法知道使用哪个T进行反序列化/写入。
1.当调用mapper.readValue时,需要显式地通知Jackson要读入的类型(包括有界类型);这是缺少的(您只是使用Example.class):

IExample example = mapper.readValue(new File(path), Example.class);

因此,要解决这些问题,你需要改变:
1.在IExample/Example中将泛型方法替换为泛型类:

...
    static interface IExample<T extends IUser> {
        T getUser();
        void setUser(T user);
    }
    
    static class Example<T extends IUser> implements IExample<T> {
        
        @JsonProperty("user")
        private T user;
        @JsonIgnore
        private Map<String, Object> additionalProperties = new HashMap<String, Object>();
        
        @JsonProperty("user")
        public T getUser() {
            return user;
        }
        
        @JsonProperty("user")
        public void setUser(T t) {
            this.user = t;
        }
...

1.通过传递适当的jackson TypeReference来通知JacksonExample有界类型:

...
    TypeReference<Example<User>> typeReference = new TypeReference<Example<User>>() { };
    IExample example = mapper.readValue(new File(path), typeReference);
...

增编:

您发现的新问题,关于额外的泛型类型IAddress/Address;不在TypeReference附近,您将其正确设置为:

TypeReference<Example<User, Address>> typeReference = new TypeReference<Example<User, Address>>() { };

问题在于接口和类中泛型类型的声明。
当您说U extends IUser & IAddress时,您是在说U扩展/实现了两者IUserIAddress;这就是为什么Jackson抱怨Address没有扩展IUser;因为它只扩展IAddress。另外,T将被隐式地约束为能够绑定到扩展java.lang.Object的任何类(而不是IUser;这可能是您所期望的),因为您没有为它指定extends...
因此,要解决此问题,请替换IExampleExample的泛型类型声明:

<T, U extends IUser & IAddress>

<T extends IUser, U extends IAddress>

Complete code on GitHub

相关问题