001    package javax.ws.rs.core;
002    
003    /*
004     * The contents of this file are subject to the terms
005     * of the Common Development and Distribution License
006     * (the "License").  You may not use this file except
007     * in compliance with the License.
008     *
009     * You can obtain a copy of the license at
010     * http://www.opensource.org/licenses/cddl1.php
011     * See the License for the specific language governing
012     * permissions and limitations under the License.
013     *
014     * This file incorporates work covered by the following copyright and
015     * permission notice:
016     *
017     * Copyright (C) 2006 Google Inc.
018     *
019     * Licensed under the Apache License, Version 2.0 (the "License");
020     * you may not use this file except in compliance with the License.
021     * You may obtain a copy of the License at
022     *
023     * http://www.apache.org/licenses/LICENSE-2.0
024     *
025     * Unless required by applicable law or agreed to in writing, software
026     * distributed under the License is distributed on an "AS IS" BASIS,
027     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
028     * See the License for the specific language governing permissions and
029     * limitations under the License.
030     */
031    import java.lang.reflect.GenericArrayType;
032    import java.lang.reflect.ParameterizedType;
033    import java.lang.reflect.Type;
034    import javax.ws.rs.ext.MessageBodyWriter;
035    
036    /**
037     * Represents a response entity of a generic type {@code T}.
038     * 
039     * <p>Normally type erasure removes generic type information such that a
040     * {@link Response} instance that contains, e.g., an entity of type
041     * {@code List<String>} appears to contain a raw {@code List<?>} at runtime.
042     * When the generic type is required to select a suitable
043     * {@link MessageBodyWriter}, this class may be used to wrap the entity and
044     * capture its generic type.</p>
045     * 
046     * <p>There are two ways to create an instance:</p>
047     * <ol>
048     * <li>Create a (typically anonymous) subclass of this 
049     * class which enables retrieval of the type information at runtime despite 
050     * type erasure. For example, the following code shows how to create a
051     * {@link Response} containing an entity of type {@code List<String>} whose
052     * generic type will be available at runtime for selection of a suitable
053     * {@link MessageBodyWriter}:
054     * 
055     * <pre>List&lt;String&gt; list = new ArrayList&lt;String&gt;();
056     *GenericEntity&lt;List&lt;String&gt;&gt; entity = new GenericEntity&lt;List&lt;String&gt;&gt;(list) {};
057     *Response response = Response.ok(entity).build();</pre>
058     *
059     * <p>where <code>list</code> is the instance of <code>List&lt;String&gt</code>
060     * that will form the response body and entity is an instance of an anonymous
061     * subclass of {@code GenericEntity}.</p></li>
062     * <li>Create an instance directly by supplying the generic type information
063     * with the entity. For example the following code shows how to create
064     * a response containing the result of a method invoked via reflection:
065     * <pre>Method method = ...;
066     *GenericEntity&lt;Object&gt; entity = new GenericEntity&lt;Object&gt;(
067     *    method.invoke(...), method.getGenericReturnType());
068     *Response response = Response.ok(entity).build();</pre></li>
069     * <p>The above obtains the generic type from the return type of the method,
070     * the raw type is the class of entity.</p> 
071     * </ol>
072     */
073    public class GenericEntity<T> {
074    
075        final Class<?> rawType;
076        final Type type;
077        final T entity;
078    
079        /**
080         * Constructs a new generic entity. Derives represented class from type
081         * parameter. Note that this constructor is protected, users should create
082         * a (usually anonymous) subclass as shown above.
083         *
084         * @param entity the entity instance, must not be null
085         * @throws IllegalArgumentException if entity is null
086         */
087        protected GenericEntity(T entity) {
088            if (entity == null) {
089                throw new IllegalArgumentException("The entity must not be null");
090            }
091            this.entity = entity;
092            this.type = getSuperclassTypeParameter(getClass());
093            this.rawType = entity.getClass();
094        }
095        
096        /**
097         * Create a new instance of GenericEntity, supplying the generic type
098         * information. The entity must be assignable to a variable of the
099         * supplied generic type, e.g. if {@code entity} is an instance of
100         * {@code ArrayList<String>} then {@code genericType} could
101         * be the same or a superclass of {@code ArrayList} with the same generic
102         * type like {@code List<String>}.
103         * @param entity the entity instance, must not be null
104         * @param genericType the generic type, must not be null
105         * @throws IllegalArgumentException if the entity is not assignable to
106         * a variable of the supplied generic type or if entity or genericType
107         * is null.
108         */
109        public GenericEntity(T entity, Type genericType) {
110            if (entity == null || genericType==null) {
111                throw new IllegalArgumentException("Arguments must not be null");
112            }
113            this.entity = entity;
114            this.rawType = entity.getClass();
115            checkTypeCompatibility(this.rawType, genericType);
116            this.type = genericType;
117        }
118        
119        private void checkTypeCompatibility(Class<?> c, Type t) {
120            if (t instanceof Class) {
121                Class<?> ct = (Class<?>)t;
122                if (ct.isAssignableFrom(c))
123                    return;
124            } else if (t instanceof ParameterizedType) {
125                ParameterizedType pt = (ParameterizedType)t;
126                Type rt = pt.getRawType();
127                checkTypeCompatibility(c, rt);
128                return;
129            } else if (c.isArray() && (t instanceof GenericArrayType)) {
130                GenericArrayType at = (GenericArrayType)t;
131                Type rt = at.getGenericComponentType();
132                checkTypeCompatibility(c.getComponentType(), rt);
133                return;
134            }
135            throw new IllegalArgumentException("The type is incompatible with the class of the entity");
136        }
137        
138        /**
139         * Returns the type from super class's type parameter.
140         */
141        private static Type getSuperclassTypeParameter(Class<?> subclass) {
142            Type superclass = subclass.getGenericSuperclass();
143            if (!(superclass instanceof ParameterizedType)) {
144                throw new RuntimeException("Missing type parameter.");
145            }
146            ParameterizedType parameterized = (ParameterizedType) superclass;
147            return parameterized.getActualTypeArguments()[0];
148        }
149    
150        /**
151         * Gets the raw type of the enclosed entity. Note that this is the raw type of
152         * the instance, not the raw type of the type parameter. I.e. in the example
153         * in the introduction, the raw type is {@code ArrayList} not {@code List}.
154         * @return the raw type
155         */
156        public final Class<?> getRawType() {
157            return rawType;
158        }
159    
160        /**
161         * Gets underlying {@code Type} instance. Note that this is derived from the
162         * type parameter, not the enclosed instance. I.e. in the example
163         * in the introduction, the type is {@code List<String>} not
164         * {@code ArrayList<String>}.
165         * @return the type
166         */
167        public final Type getType() {
168            return type;
169        }
170    
171        /**
172         * Get the enclosed entity
173         * @return the enclosed entity
174         */
175        public final T getEntity() {
176            return entity;
177        }
178    }