users@jersey.java.net

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

From: gerard davison <gerard.davison_at_oracle.com>
Date: Tue, 10 Nov 2009 15:05:46 +0000

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