Java 7 Generic: Как получить доступ к методу универсального типа? - PullRequest
0 голосов
/ 09 сентября 2018

Я работаю над устаревшим приложением, которое использует Java 7. У меня есть общий класс Request (аннотации от lombok):

@AllArgsConstructor
@Getter
public class Request<T> {
    int Id;
    T requestContext;
}

Вот один из типов requestContext:

@AllArgsConstructor
@Getter
public class StudentRequestContext {
    int ID;
    String name;
}

У меня есть интерфейс ResponseGenerator:

public interface ResponseGenerator {
    <T> Response getResponse(Request<T> request);
}

Вот класс реализатора этого интерфейса:

public class StudentResponseGenerator implements ResponseGenerator {
    @Override
    public <StudentRequestContext> Response getResponse(
        Request<StudentRequestContext> studentRequest) {
        StudentRequestContext studentRequestContext = 
          (StudentRequestContext) studentRequest.getRequestContext();
        studentRequestContext.get //NO getName METHOD IS AVAILABLE 
    }
}

Как показано в приведенном выше комментарии к коду, для объекта универсального типа studentRequestContext в классе StudentResponseGenerator класс get не доступен. Чего мне не хватает?

Ответы [ 2 ]

0 голосов
/ 10 сентября 2018

public <StudentRequestContext> Response getResponse(... означает, что вы объявляете StudentRequestContext как переменную типа , для которой этот метод является общим. Это совершенно не связано с классом с именем StudentRequestContext выше. Когда вы используете тип StudentRequestContext внутри метода, он ссылается на эту переменную типа, объявленную для этого метода, а не на тип из класса.

Чтобы избежать путаницы, вы можете переименовать переменную типа, скажем, в U, что полностью эквивалентно тому, что вы имели выше:

public <U> Response getResponse(
    Request<U> studentRequest) {
    U studentRequestContext = 
      (U) studentRequest.getRequestContext();
    studentRequestContext.get //NO getName METHOD IS AVAILABLE 
}

Видите, в чем проблема? Переменная studentRequestContext имеет тип U (переменная типа без границ), у которой нет метода с именем getName.

Подпись <T> Response getResponse(Request<T> request); означает нечто иное, чем вы, вероятно, намеревались. Сигнатура <T> Response getResponse(Request<T> request); означает, что метод реализации должен принимать аргумент типа Request из любого параметра типа (вместо этого можно эквивалентно записать сигнатуру как Response getResponse(Request<?> request);).

Вероятно, вам нужно сделать интерфейс универсальным, и его метод getResponse может принимать аргумент типа Request определенного параметра типа, такой же, как параметр типа самого ResponseGenerator:

public interface ResponseGenerator<T> {
    Response getResponse(Request<T> request);
}

Тогда ваш класс StudentResponseGenerator может реализовать этот интерфейс, используя определенный тип в качестве параметра типа:

public class StudentResponseGenerator implements ResponseGenerator<StudentRequestContext> {
    @Override
    public Response getResponse(Request<StudentRequestContext> studentRequest) {
        // ...
    }
}
0 голосов
/ 09 сентября 2018

Просто чтобы вы поняли

<T> Response getResponse(Request<T> request)
 ^    ^ 
 |     actual return type of the method
 type used with the 'request' parameter, needed to type bind args which are generic

поэтому реализация должна выглядеть примерно так:

public class StudentResponseGenerator implements ResponseGenerator {

    @Override
    public Response getResponse(
        Request<StudentRequestContext> studentRequest) { // this is where the T is inferred
        StudentRequestContext studentRequestContext = 
          (StudentRequestContext) studentRequest.getRequestContext();
        return Response.entity(studentRequestContext.getName()).build(); 
    }

}

Примечание : я не скомпилировал точный синтаксис построения Response в настоящее время.

...