Переменная типа 'T' не может быть разрешена (с контекстом класса com.yaml.Example) - PullRequest
1 голос
/ 15 мая 2019

Я новичок в дженериках 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.Пример)


UPDATE

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»

1 Ответ

2 голосов
/ 15 мая 2019

У вас 2 проблемы с кодом из-за стирания типа java ;что требует от Джексона всех конкретных типов, которые следует использовать при десериализации данных.В случае универсальных типов необходимо знать границы (конкретные классы для параметризованных типов) универсальных классов для использования.Джексон информируется об этих границах через ссылки на типы;который вы должны предоставить.Тогда у вас есть две проблемы:

  1. Насколько я знаю, Джексон не может быть проинформирован о границах общих методов (и это не имеет особого смысла).Так, в Example свойство user (public <T extends IUser> void setUser(T t)) представляет собой препятствие, поскольку Джексон не может знать, какой T использовать для десериализации / записи.

  2. Типы для чтения (включая ограниченные) должны быть явно сообщены Джексону при вызове mapper.readValue;который отсутствует (вы просто используете 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;
        }
...
Сообщите Джексону ограниченного типа 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>
...