On 09/11/2009 08:55, Paul Sandoz wrote:
> On Nov 6, 2009, at 6:23 PM, 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.
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).
// 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