我是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();
}
}
我希望输出为: Test User ,但实际输出为 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
的声明中遇到错误:类型参数“地址”不在其范围内,应实现“ IUser”
答案 0 :(得分:2)
由于java's type erasure,您的代码有2个问题;这需要杰克逊知道所有反序列化数据时要使用的具体类型。对于泛型类型,它需要知道要使用的泛型类的范围(参数化类型的具体类)。杰克逊通过类型引用获悉了这个界限。您需要提供。那么您遇到的两个问题是:
据我所知,无法告知Jackson泛型方法的范围(这没有多大意义)。因此,在Example
中,属性user
(public <T extends IUser> void setUser(T t)
)表示一个障碍,因为杰克逊无法知道使用哪个T
来反序列化/写入。 p>
在调用mapper.readValue
时,需要将要读入的类型(包括有界的类型)显式通知杰克逊。哪个丢失了(您只是在使用Example.class
):
IExample example = mapper.readValue(new File(path), Example.class);
因此,要解决这些问题,您需要更改:
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;
}
...
Example
来通知TypeReference
有界类型的杰克逊:...
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
扩展/实现了两者 IUser
和IAddress
;这就是杰克逊抱怨Address
没有扩展IUser
的原因;因为它仅扩展IAddress
。此外,由于T
没有被指定为可以绑定到任何扩展java.lang.Object
的类(而不是IUser
;这是您可能期望的),因此可以绑定到该类。为此extends...
。
因此,要解决此问题,请替换IExample
和Example
的通用类型声明:
<T, U extends IUser & IAddress>
使用
<T extends IUser, U extends IAddress>