1

I am working on a legacy application which uses Java 7. I have a generic Request class (annotations are from lombok):

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

Here is one of the requestContext type:

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

I have a ResponseGenerator interface:

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

Here is the implementer class of this interface:

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 
    }
}

As shown in the code comment above no getter is available for generic type studentRequestContext object in StudentResponseGenerator class. What am I missing?

amy
  • 257
  • 1
  • 3
  • 10
  • 1
    who is telling you that the method doesn't exist? Your IDE? Is it aware of lombok? – njzk2 Sep 09 '18 at 04:53
  • 1
    That seems more of a setup issue. Maybe your IDE isn't configured correctly to use Lombok? You see, you class doesn't have getter methods. Until Lombok kicks in and generates them! – GhostCat Sep 09 '18 at 04:54
  • Yes, the methods are not showing up on IntelliJ. I use lombok in other places of the application. I also tried by adding getters manually but that did not help. – amy Sep 09 '18 at 16:25

2 Answers2

1

public <StudentRequestContext> Response getResponse(... means you are declaring StudentRequestContext as a type variable that this method is generic on. It is completely unrelated to the class named StudentRequestContext above. When you use the type StudentRequestContext inside the method, it is referring to this type variable declared for this method, and not the type from the class.

To avoid confusion, you can rename the type variable to, let's say, U, which is completely equivalent to what you have above:

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

See what the problem is? The variable studentRequestContext has type U (a type variable with no bounds), which has no method called getName.

The signature <T> Response getResponse(Request<T> request); means something different than what you probably intended. The signature <T> Response getResponse(Request<T> request); means the implementing method must accept an argument of type Request of any type parameter (you could equivalently write the signature as Response getResponse(Request<?> request); instead).

What you probably wanted is to make the interface generic, and have its getResponse method accept an argument of type Request of a specific type parameter, one that is the same as the type parameter of ResponseGenerator itself:

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

Then your StudentResponseGenerator class can implement that interface using a specific type as the type parameter:

public class StudentResponseGenerator implements ResponseGenerator<StudentRequestContext> {
    @Override
    public Response getResponse(Request<StudentRequestContext> studentRequest) {
        // ...
    }
}
newacct
  • 119,665
  • 29
  • 163
  • 224
0

Just to make you understand

<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

so the implementation should look something like

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(); 
    }

}

Note: I haven't compiled the exact syntax of building the Response currently.

Naman
  • 27,789
  • 26
  • 218
  • 353
  • Thanks for your response! Actually that was a typo in my original post that I missed the return type (Response) in the @Override method. Even with that when I try to access the getName() method on object studentRequestContext, it does not show up. Looks like I am missing something else. – amy Sep 09 '18 at 16:24