users@jersey.java.net

Re: [Jersey] FW: xml schema in request and response (wadl)

From: Marc Hadley <Marc.Hadley_at_Sun.COM>
Date: Tue, 10 Nov 2009 10:41:44 -0500

On Nov 10, 2009, at 10:05 AM, gerard davison wrote:
>>>>>> 3. Response type
>>>>>>
>>>>>> This would be a strong argument for adding a generic parameter
>>>>>> to the Response/ResponseBuilder interfaces;
>>>>>
>>>>> Marc and I tried and failed miserably. We could not get things
>>>>> to work with type safety using the response building pattern.
>>>>>
>>>> Yes, I forget the exact problem no but we couldn't get it to work
>>>> satisfactorily. We settled on the GenericEntity class to capture
>>>> the generic type for use with Response or non-committal return
>>>> types like Object. Unfortunately this only works at runtime and
>>>> isn't any use for WADL generation.
>>>
>>> I would be interesting to understand better why it didn't work for
>>> you if you have time.
>>
>> Oh crap... often when one experiments with a fresh mind one can
>> find a solution (see end of email).
>>
>> The problem we were having was we could not connect the T of the
>> static method on Response to the T of the
>> Response.ResponseBuilder. There is a less known (well at least to
>> me at the time) of declaring T right before the declaration of the
>> static method call, for example:
>>
>> List<String> l = Collections.<String>emptyList();
>>
>> <blush/> this is all rather embarrassing...
>
> Well the only place I have ever seen this is in Effective Java 2ed,
> so like you I hadn't heard of this language feature until this year.
> It is very much a language feature that gets lost down the back of
> the sofa. I would guess if you asked 100 java programmers only 1 or
> 2 would have heard of it.
>
Indeed, I can imagine a lot of puzzled questions arising if we
required developers to do that.

> The other solution that occurs to me and I have seen often used is
> to not bind the type in the builder until it is specified see below.
> The trick is to create a new instance of ResponseBuilder when we
> need to bind in the type; and pass in the internal state. Until the
> call to entity(...) the generic parameter T is unbound. (I have
> included the GenericEntity case; but I am not sure it would be
> required if the interface is properly generic).
>
This looks like an interesting approach. Its too late now to do
anything for 1.1 but I think we should look at this for 2.0. Would you
create an issue at https://jsr311.dev.java.net/servlets/ProjectIssues
and include this suggestion so we can track it when we make a start on
the next version of the API.

Thanks,
Marc.


> // Generified Response
> ~
> public class Response<T> {
>
> static class GListString extends GenericEntity<List<String>> {
> public GListString(List<String> list) {
> super(list);
> }
> }
>
> private final T entity;
>
> private Response(T entity) {
> this.entity = entity;
> }
>
> public T getEntity() {
> return entity;
> }
> public static <T> ResponseBuilder<T> start() {
> return new ResponseBuilder<T>("Some State");
> }
> public static class ResponseBuilder<T> {
>
> private Object state;
> private Type type;
> private T entity;
>
> public ResponseBuilder(Object state) {
> this.state = state;
> }
>
> public ResponseBuilder(Object state, Type type, T object) {
> this(state);
> this.type = type;
> this.entity = object;
> }
> public ResponseBuilder<T> header(String name,
> String value) {
> return this;
> }
>
>
> public <T, K extends GenericEntity<T>> ResponseBuilder<T>
> entity(K ent) {
> return new ResponseBuilder<T>(state, ent.getType(),
> ent.getEntity());
> }
>
> public <T> ResponseBuilder<T> entity(T ent) {
> return new ResponseBuilder<T>(state, ent.getClass(), ent);
> }
>
> public Response<T> build() {
> return new Response<T>(entity);
> }
>
> }
>
>
> public static void main(String[] args) {
>
> List<String> list = new ArrayList<String>();
> GListString genericList =
> new GListString(list);
>
> Response<List<String>> response = Response
> .start()
> .header("Content-Type", "fudge")
> .entity(list)
> .build();
>
> // Using generic entity
> //
>
> Response<List<String>> genericResponse = Response
> .start()
> .header("Content-Type", "fudge")
> .entity(genericList)
> .build();
>
> // String example
> //
> Response<String> stringResponse = Response
> .start() // ResponseBuilder<?>
> .entity("String") // ResponseBuilder<String>
> .header("Content-Type", "cheese") // ResponseBuilder<String>
> .build();
> }
>
> }
>
>
>>
>> Unfortunately it is too late to make changes to JAX-RS 1.1. I could
>> add something to Jersey in the interim.
>
> Damm, I figured as much. Do I need to raise this as an issue for
> this for the next release. I guess I am going to have to wait until
> 2.x for this. As to a workaround, it would be useful the WADL issue,
> I guess it could as simple as a generic subtype of these classes. I
> guess I will log that with the root issue which stated this
> discussion, hopefully I will have this done in a few days.
>
> Cheers,
>
> Gerard
>
>>
>> Paul.
>>
>>
>> public class Main {
>>
>> public static class Response<T> {
>>
>> private final T entity;
>>
>> private Response(T entity) {
>> this.entity = entity;
>> }
>>
>> public T getEntity() {
>> return entity;
>> }
>>
>> public static class ResponseBuilder<T> {
>> private T entity;
>>
>> public ResponseBuilder<T> entity(T entity) {
>> this.entity = entity;
>> return this;
>> }
>>
>> public Response<T> build() {
>> return new Response<T>(entity);
>> }
>>
>> static protected <T> ResponseBuilder<T> newInstance() {
>> return
>> RuntimeDelegate.getInstance().<T>createResponseBuilder();
>> }
>> }
>>
>> static public <T> ResponseBuilder<T> start() {
>> return new ResponseBuilder<T>();
>> }
>>
>> }
>>
>> public static class RuntimeDelegate {
>> public static RuntimeDelegate getInstance() {
>> return new RuntimeDelegate();
>> }
>>
>> public <T> Response.ResponseBuilder<T>
>> createResponseBuilder() {
>> return new Response.ResponseBuilder<T>();
>> }
>> }
>>
>> /**
>> * @param args the command line arguments
>> */
>> public static void main(String[] args) {
>> Response<String> r =
>> Response.<String>start().entity("xx").build();
>>
>> String e = r.getEntity();
>> System.out.println(e);
>> }
>> }
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
>> For additional commands, e-mail: users-help_at_jersey.dev.java.net
>>
>
> --
> Gerard Davison | Senior Principal Software Engineer | +44 118 924 5095
> Oracle JDeveloper Web Service Tooling Development
> Oracle Corporation UK Ltd is a company incorporated in England &
> Wales.
> Company Reg. No. 1782505.
> Reg. office: Oracle Parkway, Thames Valley Park, Reading RG6 1RA.
>
> Blog http://kingsfleet.blogspot.com
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
> For additional commands, e-mail: users-help_at_jersey.dev.java.net
>