
org.glassfish.jersey.message.internal.MessageBodyFactory Maven / Gradle / Ivy
Go to download
A bundle project producing JAX-RS RI bundles. The primary artifact is an "all-in-one" OSGi-fied JAX-RS RI bundle
(jaxrs-ri.jar).
Attached to that are two compressed JAX-RS RI archives. The first archive (jaxrs-ri.zip) consists of binary RI bits and
contains the API jar (under "api" directory), RI libraries (under "lib" directory) as well as all external
RI dependencies (under "ext" directory). The secondary archive (jaxrs-ri-src.zip) contains buildable JAX-RS RI source
bundle and contains the API jar (under "api" directory), RI sources (under "src" directory) as well as all external
RI dependencies (under "ext" directory). The second archive also contains "build.xml" ANT script that builds the RI
sources. To build the JAX-RS RI simply unzip the archive, cd to the created jaxrs-ri directory and invoke "ant" from
the command line.
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 2010-2013 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can
* obtain a copy of the License at
* http://glassfish.java.net/public/CDDL+GPL_1_1.html
* or packager/legal/LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at packager/legal/LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [year] [name of copyright owner]"
*
* Contributor(s):
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
package org.glassfish.jersey.message.internal;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import javax.ws.rs.Consumes;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Configuration;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.MessageBodyReader;
import javax.ws.rs.ext.MessageBodyWriter;
import javax.ws.rs.ext.ReaderInterceptor;
import javax.ws.rs.ext.WriterInterceptor;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.glassfish.jersey.internal.PropertiesDelegate;
import org.glassfish.jersey.internal.inject.Providers;
import org.glassfish.jersey.internal.util.KeyComparator;
import org.glassfish.jersey.internal.util.KeyComparatorHashMap;
import org.glassfish.jersey.internal.util.KeyComparatorLinkedHashMap;
import org.glassfish.jersey.internal.util.PropertiesHelper;
import org.glassfish.jersey.internal.util.ReflectionHelper;
import org.glassfish.jersey.internal.util.ReflectionHelper.DeclaringClassInterfacePair;
import org.glassfish.jersey.message.MessageBodyWorkers;
import org.glassfish.jersey.message.MessageProperties;
import org.glassfish.hk2.api.ServiceLocator;
import org.glassfish.hk2.utilities.binding.AbstractBinder;
import org.jvnet.hk2.annotations.Optional;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.google.common.primitives.Primitives;
/**
* A factory for managing {@link MessageBodyReader}, {@link MessageBodyWriter} instances.
*
* @author Paul Sandoz
* @author Marek Potociar (marek.potociar at oracle.com)
* @author Jakub Podlesak (jakub.podlesak at oracle.com)
*/
public class MessageBodyFactory implements MessageBodyWorkers {
/**
* Message body factory injection binder.
*/
public static class Binder extends AbstractBinder {
@Override
protected void configure() {
bindAsContract(MessageBodyFactory.class).to(MessageBodyWorkers.class).in(Singleton.class);
}
}
/**
* Media type comparator.
*/
public static final KeyComparator MEDIA_TYPE_COMPARATOR =
new KeyComparator() {
private static final long serialVersionUID = 2727819828630827763L;
@Override
public boolean equals(MediaType x, MediaType y) {
return x.getType().equalsIgnoreCase(y.getType())
&& x.getSubtype().equalsIgnoreCase(y.getSubtype());
}
@Override
public int hash(MediaType k) {
return k.getType().toLowerCase().hashCode()
+ k.getSubtype().toLowerCase().hashCode();
}
// move to separate comparator?
@Override
public int compare(MediaType o1, MediaType o2) {
if (equals(o1, o2)) {
return 0;
} else if (o1.isWildcardType() ^ o2.isWildcardType()) {
return (o1.isWildcardType()) ? 1 : -1;
} else if (o1.isWildcardSubtype() ^ o2.isWildcardSubtype()) {
return (o1.isWildcardSubtype()) ? 1 : -1;
}
return 0;
}
};
/**
* Compares message body workers by providing class (most specific first) and assigned media types if provider classes are
* the same.
*/
private static final Comparator> WORKER_BY_TYPE_COMPARATOR =
new Comparator>() {
@Override
public int compare(final MessageBodyWorkerPair> o1, final MessageBodyWorkerPair> o2) {
final Class> o1ProviderClassParam = o1.providerClassParam;
final Class> o2ProviderClassParam = o2.providerClassParam;
if (o1ProviderClassParam == o2ProviderClassParam) {
// Compare producible media types.
return compare(o2.types, o1.types);
} else if (o1ProviderClassParam.isAssignableFrom(o2ProviderClassParam)) {
return 1;
} else if (o2ProviderClassParam.isAssignableFrom(o1ProviderClassParam)) {
return -1;
}
return 0;
}
private int compare(List mediaTypeList1, List mediaTypeList2) {
mediaTypeList1 = mediaTypeList1.isEmpty() ? MediaTypes.GENERAL_MEDIA_TYPE_LIST : mediaTypeList1;
mediaTypeList2 = mediaTypeList2.isEmpty() ? MediaTypes.GENERAL_MEDIA_TYPE_LIST : mediaTypeList2;
return MediaTypes.MEDIA_TYPE_LIST_COMPARATOR.compare(mediaTypeList2, mediaTypeList1);
}
};
private final ServiceLocator locator;
private final Boolean legacyProviderOrdering;
private List> readers;
private List> writers;
private final Map> readersCache =
new KeyComparatorHashMap>(MEDIA_TYPE_COMPARATOR);
private final Map> writersCache =
new KeyComparatorHashMap>(MEDIA_TYPE_COMPARATOR);
private final Map, List> mbrTypeLookupCache =
new ConcurrentHashMap, List>();
private final Map, List> mbwTypeLookupCache =
new ConcurrentHashMap, List>();
private final Map, List> typeToMediaTypeReadersCache =
new ConcurrentHashMap, List>();
private final Map, List> typeToMediaTypeWritersCache =
new ConcurrentHashMap, List>();
private final Map>> mbrLookupCache =
new ConcurrentHashMap>>();
private final Map>> mbwLookupCache =
new ConcurrentHashMap>>();
private static class MessageBodyWorkerPair {
private final T provider;
private final List types;
private final Boolean custom;
private final Class> providerClassParam;
public MessageBodyWorkerPair(final T provider, final List types, final Boolean custom, final Boolean isReader) {
this.provider = provider;
this.types = types;
this.custom = custom;
this.providerClassParam = getProviderClassParam(isReader);
}
private Class> getProviderClassParam(final boolean isReader) {
final ReflectionHelper.DeclaringClassInterfacePair pair = ReflectionHelper.getClass(provider.getClass(),
isReader ? MessageBodyReader.class : MessageBodyWriter.class);
final Class[] classArgs = ReflectionHelper.getParameterizedClassArguments(pair);
return classArgs != null ? classArgs[0] : Object.class;
}
}
/**
* Create new message body workers factory.
*
* @param locator service locator.
* @param configuration configuration. Optional - can be null.
*/
@Inject
public MessageBodyFactory(ServiceLocator locator, @Optional Configuration configuration) {
this.locator = locator;
this.legacyProviderOrdering = configuration != null
&& PropertiesHelper.isProperty(configuration.getProperty(MessageProperties.LEGACY_WORKERS_ORDERING));
initReaders();
initWriters();
}
/**
* Compares 2 instances implementing/inheriting the same super-type and returns
* which of the two instances has the super-type declaration closer in it's
* inheritance hierarchy tree.
*
* The comparator is optimized to cache results of the previous distance declaration
* computations.
*
* @param common super-type used for computing the declaration distance and
* comparing instances.
*/
private static class DeclarationDistanceComparator implements Comparator {
private final Class declared;
private final Map distanceMap = new HashMap();
DeclarationDistanceComparator(Class declared) {
this.declared = declared;
}
@Override
public int compare(T o1, T o2) {
int d1 = getDistance(o1);
int d2 = getDistance(o2);
return d2 - d1;
}
private int getDistance(T t) {
Integer distance = distanceMap.get(t.getClass());
if (distance != null) {
return distance;
}
DeclaringClassInterfacePair p = ReflectionHelper.getClass(
t.getClass(), declared);
Class[] as = ReflectionHelper.getParameterizedClassArguments(p);
Class a = (as != null) ? as[0] : null;
distance = 0;
while (a != null && a != Object.class) {
distance++;
a = a.getSuperclass();
}
distanceMap.put(t.getClass(), distance);
return distance;
}
}
/**
* {@link MessageBodyWorkerPair} comparator which works as it is described in JAX-RS 2.x specification.
*
* Pairs are sorted by distance from required type, media type and custom/provided (provided goes first).
*
* @param MessageBodyReader or MessageBodyWriter.
* @see DeclarationDistanceComparator
* @see #MEDIA_TYPE_COMPARATOR
*/
private static class WorkerComparator implements Comparator> {
final Class wantedType;
final MediaType wantedMediaType;
private WorkerComparator(Class wantedType, MediaType wantedMediaType) {
this.wantedType = wantedType;
this.wantedMediaType = wantedMediaType;
}
@Override
public int compare(MessageBodyWorkerPair mbwp1, MessageBodyWorkerPair mbwp2) {
final int distance = compareTypeDistances(mbwp1.providerClassParam, mbwp2.providerClassParam);
if (distance != 0) {
return distance;
}
final int mediaTypeComparison = getMediaTypeDistance(wantedMediaType, mbwp1.types) - getMediaTypeDistance(wantedMediaType, mbwp2.types);
if (mediaTypeComparison != 0) {
return mediaTypeComparison;
}
if (mbwp1.custom ^ mbwp2.custom) {
return (mbwp1.custom) ? -1 : 1;
}
return 0;
}
private int getMediaTypeDistance(MediaType wanted, List mtl) {
if (wanted == null) {
return 0;
}
int distance = 2;
for (MediaType mt : mtl) {
if (MediaTypes.typeEqual(wanted, mt)) {
return 0;
}
if (distance > 1 && MediaTypes.typeEqual(MediaTypes.getTypeWildCart(wanted), mt)) {
distance = 1;
}
}
return distance;
}
private int compareTypeDistances(Class> providerClassParam1, Class> providerClassParam2) {
return getTypeDistance(providerClassParam1) - getTypeDistance(providerClassParam2);
}
private int getTypeDistance(Class> classParam) {
// cache?
Class> tmp1 = wantedType;
Class> tmp2 = classParam;
final Iterator> it1 = getClassHierarchyIterator(tmp1);
final Iterator> it2 = getClassHierarchyIterator(tmp2);
int distance = 0;
while (!wantedType.equals(tmp2) && !classParam.equals(tmp1)) {
distance++;
if (!wantedType.equals(tmp2)) {
tmp2 = it2.hasNext() ? it2.next() : null;
}
if (!classParam.equals(tmp1)) {
tmp1 = it1.hasNext() ? it1.next() : null;
}
if (tmp2 == null && tmp1 == null) {
return Integer.MAX_VALUE;
}
}
return distance;
}
private Iterator> getClassHierarchyIterator(final Class> classParam) {
if (classParam == null) {
return Collections.>emptyList().iterator();
}
final ArrayList> classes = new ArrayList>();
final LinkedList> unprocessed = new LinkedList>();
unprocessed.add(classParam);
while (!unprocessed.isEmpty()) {
final Class> clazz = unprocessed.removeFirst();
classes.add(clazz);
unprocessed.addAll(Arrays.asList(clazz.getInterfaces()));
final Class> superclazz = clazz.getSuperclass();
if (superclazz != null) {
unprocessed.add(superclazz);
}
}
return classes.iterator();
}
}
/**
* {@link MessageBodyWorkerPair} comparator which works as it is described in JAX-RS 1.x specification.
*
* Pairs are sorted by custom/provided (custom goes first), media type and declaration distance.
*
* @param MessageBodyReader or MessageBodyWriter.
* @see DeclarationDistanceComparator
* @see #MEDIA_TYPE_COMPARATOR
*/
private static class LegacyWorkerComparator implements Comparator> {
final DeclarationDistanceComparator distanceComparator;
private LegacyWorkerComparator(Class type) {
distanceComparator = new DeclarationDistanceComparator(type);
}
@Override
public int compare(MessageBodyWorkerPair mbwp1, MessageBodyWorkerPair mbwp2) {
if (mbwp1.custom ^ mbwp2.custom) {
return (mbwp1.custom) ? -1 : 1;
}
final int mediaTypeComparison = MEDIA_TYPE_COMPARATOR.compare(mbwp1.types.get(0), mbwp2.types.get(0));
if (mediaTypeComparison != 0) {
return mediaTypeComparison;
}
return distanceComparator.compare(mbwp1.provider, mbwp2.provider);
}
}
private static class TypeMediaTypePair {
final Class> clazz;
final MediaType mediaType;
private TypeMediaTypePair(Class> clazz, MediaType mediaType) {
this.clazz = clazz;
this.mediaType = mediaType;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
TypeMediaTypePair that = (TypeMediaTypePair) o;
return !(clazz != null ? !clazz.equals(that.clazz) : that.clazz != null) &&
!(mediaType != null ? !mediaType.equals(that.mediaType) : that.mediaType != null);
}
@Override
public int hashCode() {
int result = clazz != null ? clazz.hashCode() : 0;
result = 31 * result + (mediaType != null ? mediaType.hashCode() : 0);
return result;
}
}
private void initReaders() {
this.readers = new ArrayList>();
final Set customProviders = Providers.getCustomProviders(locator, MessageBodyReader.class);
final Set providers = Providers.getProviders(locator, MessageBodyReader.class);
initReaders(readers, customProviders, true);
providers.removeAll(customProviders);
initReaders(readers, providers, false);
if (legacyProviderOrdering) {
Collections.sort(readers, new LegacyWorkerComparator(MessageBodyReader.class));
for (MessageBodyWorkerPair messageBodyWorkerPair : readers) {
for (MediaType mt : messageBodyWorkerPair.types) {
List readerList = readersCache.get(mt);
if (readerList == null) {
readerList = new ArrayList();
readersCache.put(mt, readerList);
}
readerList.add(messageBodyWorkerPair.provider);
}
}
}
}
private void initReaders(List> readers, Set providersSet,
boolean custom) {
for (MessageBodyReader provider : providersSet) {
List values = MediaTypes.createFrom(provider.getClass().getAnnotation(Consumes.class));
readers.add(new MessageBodyWorkerPair(provider, values, custom, true));
}
}
private void initWriters() {
this.writers = new ArrayList>();
final Set customProviders = Providers.getCustomProviders(locator, MessageBodyWriter.class);
final Set providers = Providers.getProviders(locator, MessageBodyWriter.class);
initWriters(writers, customProviders, true);
providers.removeAll(customProviders);
initWriters(writers, providers, false);
if (legacyProviderOrdering) {
Collections.sort(writers, new LegacyWorkerComparator(MessageBodyWriter.class));
for (MessageBodyWorkerPair messageBodyWorkerPair : writers) {
for (MediaType mt : messageBodyWorkerPair.types) {
List writerList = writersCache.get(mt);
if (writerList == null) {
writerList = new ArrayList();
writersCache.put(mt, writerList);
}
writerList.add(messageBodyWorkerPair.provider);
}
}
}
}
private void initWriters(List> writers, Set providersSet,
boolean custom) {
for (MessageBodyWriter provider : providersSet) {
List values = MediaTypes.createFrom(provider.getClass().getAnnotation(Produces.class));
writers.add(new MessageBodyWorkerPair(provider, values, custom, false));
}
}
// MessageBodyWorkers
@Override
public Map> getReaders(MediaType mediaType) {
Map> subSet =
new KeyComparatorLinkedHashMap>(
MEDIA_TYPE_COMPARATOR);
getCompatibleProvidersMap(mediaType, readers, subSet);
return subSet;
}
@Override
public Map> getWriters(MediaType mediaType) {
Map> subSet =
new KeyComparatorLinkedHashMap>(
MEDIA_TYPE_COMPARATOR);
getCompatibleProvidersMap(mediaType, writers, subSet);
return subSet;
}
@Override
public String readersToString(Map> readers) {
return toString(readers);
}
@Override
public String writersToString(Map> writers) {
return toString(writers);
}
private String toString(Map> set) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
for (Map.Entry> e : set.entrySet()) {
pw.append(e.getKey().toString()).println(" ->");
for (T t : e.getValue()) {
pw.append(" ").println(t.getClass().getName());
}
}
pw.flush();
return sw.toString();
}
@Override
public MessageBodyReader getMessageBodyReader(Class c, Type t,
Annotation[] as,
MediaType mediaType) {
MessageBodyReader p = null;
if (legacyProviderOrdering) {
if (mediaType != null) {
p = _getMessageBodyReader(c, t, as, mediaType, mediaType);
if (p == null) {
p = _getMessageBodyReader(c, t, as, mediaType,
MediaTypes.getTypeWildCart(mediaType));
}
}
if (p == null) {
p = _getMessageBodyReader(c, t, as, mediaType, MediaTypes.GENERAL_MEDIA_TYPE);
}
} else {
p = _getMessageBodyReader(c, t, as, mediaType, readers);
}
return p;
}
@Override
@SuppressWarnings("unchecked")
public List getMessageBodyReaderMediaTypes(Class> type, Type genericType, Annotation[] annotations) {
final Set readableMediaTypes = Sets.newLinkedHashSet();
for (MessageBodyWorkerPair mbrp : readers) {
boolean readableWorker = false;
for (MediaType mt : mbrp.types) {
if (mbrp.provider.isReadable(type, genericType, annotations, mt)) {
readableMediaTypes.add(mt);
readableWorker = true;
}
if (!readableMediaTypes.contains(MediaType.WILDCARD_TYPE)
&& readableWorker
&& mbrp.types.contains(MediaType.WILDCARD_TYPE)) {
readableMediaTypes.add(MediaType.WILDCARD_TYPE);
}
}
}
final List mtl = Lists.newArrayList(readableMediaTypes);
Collections.sort(mtl, MediaTypes.MEDIA_TYPE_COMPARATOR);
return mtl;
}
@SuppressWarnings("unchecked")
private boolean isCompatible(MessageBodyWorkerPair messageBodyWorkerPair, Class c, MediaType mediaType) {
if (messageBodyWorkerPair.providerClassParam.equals(Object.class) ||
// looks weird. Could/(should?) be separated to Writer/Reader check
messageBodyWorkerPair.providerClassParam.isAssignableFrom(c) ||
c.isAssignableFrom(messageBodyWorkerPair.providerClassParam)
) {
for (MediaType mt : messageBodyWorkerPair.types) {
if (mediaType == null) {
return true;
}
if (MediaTypes.typeEqual(mediaType, mt) ||
MediaTypes.typeEqual(MediaTypes.getTypeWildCart(mediaType), mt) ||
MediaTypes.typeEqual(MediaTypes.GENERAL_MEDIA_TYPE, mt)) {
return true;
}
}
}
return false;
}
@SuppressWarnings("unchecked")
private MessageBodyReader _getMessageBodyReader(Class c, Type t,
Annotation[] as,
MediaType mediaType,
List> workers) {
List> readers = mbrLookupCache.get(new TypeMediaTypePair(c, mediaType));
if (readers == null) {
readers = new ArrayList>();
for (MessageBodyWorkerPair mbwp : workers) {
if (isCompatible(mbwp, c, mediaType)) {
readers.add(mbwp);
}
}
Collections.sort(readers, new WorkerComparator(c, mediaType));
mbrLookupCache.put(new TypeMediaTypePair(c, mediaType), readers);
}
if (readers.isEmpty()) {
return null;
}
for (MessageBodyWorkerPair mbwp : readers) {
if (mbwp.provider.isReadable(c, t, as, mediaType)) {
return mbwp.provider;
}
}
return null;
}
@SuppressWarnings("unchecked")
private MessageBodyReader _getMessageBodyReader(Class c, Type t,
Annotation[] as,
MediaType mediaType, MediaType lookup) {
List readers = readersCache.get(lookup);
if (readers == null) {
return null;
}
for (MessageBodyReader> p : readers) {
if (p.isReadable(c, t, as, mediaType)) {
return (MessageBodyReader) p;
}
}
return null;
}
@Override
public MessageBodyWriter getMessageBodyWriter(Class c, Type t,
Annotation[] as,
MediaType mediaType) {
MessageBodyWriter p = null;
if (legacyProviderOrdering) {
if (mediaType != null) {
p = _getMessageBodyWriter(c, t, as, mediaType, mediaType);
if (p == null) {
p = _getMessageBodyWriter(c, t, as, mediaType,
MediaTypes.getTypeWildCart(mediaType));
}
}
if (p == null) {
p = _getMessageBodyWriter(c, t, as, mediaType, MediaTypes.GENERAL_MEDIA_TYPE);
}
} else {
p = _getMessageBodyWriter(c, t, as, mediaType, writers);
}
return p;
}
@SuppressWarnings("unchecked")
private MessageBodyWriter _getMessageBodyWriter(Class c, Type t,
Annotation[] as,
MediaType mediaType,
List> workers) {
List> writers = mbwLookupCache.get(new TypeMediaTypePair(c, mediaType));
if (writers == null) {
writers = new ArrayList>();
for (MessageBodyWorkerPair mbwp : workers) {
if (isCompatible(mbwp, c, mediaType)) {
writers.add(mbwp);
}
}
Collections.sort(writers, new WorkerComparator(c, mediaType));
mbwLookupCache.put(new TypeMediaTypePair(c, mediaType), writers);
}
if (writers.isEmpty()) {
return null;
}
for (MessageBodyWorkerPair mbwp : writers) {
if (mbwp.provider.isWriteable(c, t, as, mediaType)) {
return mbwp.provider;
}
}
return null;
}
@SuppressWarnings("unchecked")
private MessageBodyWriter _getMessageBodyWriter(Class c, Type t,
Annotation[] as,
MediaType mediaType, MediaType lookup) {
List writers = writersCache.get(lookup);
if (writers == null) {
return null;
}
for (MessageBodyWriter> p : writers) {
if (p.isWriteable(c, t, as, mediaType)) {
return (MessageBodyWriter) p;
}
}
return null;
}
private void getCompatibleProvidersMap(MediaType mediaType,
List> set,
Map> subSet) {
if (mediaType.isWildcardType()) {
getCompatibleProvidersList(mediaType, set, subSet);
} else if (mediaType.isWildcardSubtype()) {
getCompatibleProvidersList(mediaType, set, subSet);
getCompatibleProvidersList(MediaTypes.GENERAL_MEDIA_TYPE, set, subSet);
} else {
getCompatibleProvidersList(mediaType, set, subSet);
getCompatibleProvidersList(
MediaTypes.getTypeWildCart(mediaType),
set, subSet);
getCompatibleProvidersList(MediaTypes.GENERAL_MEDIA_TYPE, set, subSet);
}
}
private void getCompatibleProvidersList(MediaType mediaType,
List> set,
Map> subSet) {
List providers = new ArrayList();
for (MessageBodyWorkerPair mbpp : set) {
if (mbpp.types.contains(mediaType)) {
providers.add(mbpp.provider);
}
}
if (!providers.isEmpty()) {
subSet.put(mediaType, Collections.unmodifiableList(providers));
}
}
@Override
@SuppressWarnings("unchecked")
public List getMessageBodyWriterMediaTypes(Class> c, Type t, Annotation[] as) {
final Set writeableMediaTypes = Sets.newLinkedHashSet();
for (MessageBodyWorkerPair mbwp : writers) {
boolean writeableWorker = false;
for (MediaType mt : mbwp.types) {
if (mbwp.provider.isWriteable(c, t, as, mt)) {
writeableMediaTypes.add(mt);
writeableWorker = true;
}
if (!writeableMediaTypes.contains(MediaType.WILDCARD_TYPE)
&& writeableWorker
&& mbwp.types.contains(MediaType.WILDCARD_TYPE)) {
writeableMediaTypes.add(MediaType.WILDCARD_TYPE);
}
}
}
final List mtl = Lists.newArrayList(writeableMediaTypes);
Collections.sort(mtl, MediaTypes.MEDIA_TYPE_COMPARATOR);
return mtl;
}
@Override
@SuppressWarnings("unchecked")
public List getMessageBodyWritersForType(final Class> clazz) {
if (!mbwTypeLookupCache.containsKey(clazz)) {
processMessageBodyWritersForType(clazz);
}
return mbwTypeLookupCache.get(clazz);
}
private void processMessageBodyWritersForType(final Class> clazz) {
final List> suitableWriters = Lists.newArrayList();
if (Response.class.isAssignableFrom(clazz)) {
suitableWriters.addAll(writers);
} else {
for (final MessageBodyWorkerPair workerPair : writers) {
final Class> wrapped = Primitives.wrap(clazz);
if (workerPair.providerClassParam == null
|| workerPair.providerClassParam.isAssignableFrom(wrapped)
|| workerPair.providerClassParam== clazz) {
suitableWriters.add(workerPair);
}
}
}
// Type -> MediaType.
typeToMediaTypeWritersCache.put(clazz, getMessageBodyWorkersMediaTypesByType(suitableWriters));
// Type -> Writer.
Collections.sort(suitableWriters, WORKER_BY_TYPE_COMPARATOR);
final List writers = Lists.newArrayList();
for (final MessageBodyWorkerPair workerPair : suitableWriters) {
writers.add(workerPair.provider);
}
mbwTypeLookupCache.put(clazz, writers);
}
@Override
public List getMessageBodyWriterMediaTypesByType(final Class> type) {
if (!typeToMediaTypeWritersCache.containsKey(type)) {
processMessageBodyWritersForType(type);
}
return typeToMediaTypeWritersCache.get(type);
}
@Override
public List getMessageBodyReaderMediaTypesByType(final Class> type) {
if (!typeToMediaTypeReadersCache.containsKey(type)) {
processMessageBodyReadersForType(type);
}
return typeToMediaTypeReadersCache.get(type);
}
@SuppressWarnings("unchecked")
private List getMessageBodyWorkersMediaTypesByType(final List> workers) {
final Set mediaTypeSet = Sets.newHashSet();
for (final MessageBodyWorkerPair mbwp : workers) {
mediaTypeSet.addAll(mbwp.types);
}
final List mediaTypes = Lists.newArrayList(mediaTypeSet);
Collections.sort(mediaTypes, MediaTypes.MEDIA_TYPE_COMPARATOR);
return mediaTypes;
}
@Override
@SuppressWarnings("unchecked")
public List getMessageBodyReadersForType(final Class> clazz) {
if (!mbrTypeLookupCache.containsKey(clazz)) {
processMessageBodyReadersForType(clazz);
}
return mbrTypeLookupCache.get(clazz);
}
private void processMessageBodyReadersForType(final Class> clazz) {
final List> suitableReaders = Lists.newArrayList();
for (MessageBodyWorkerPair workerPair : readers) {
final Class> wrapped = Primitives.wrap(clazz);
if (workerPair.providerClassParam == null
|| workerPair.providerClassParam.isAssignableFrom(wrapped)
|| workerPair.providerClassParam == clazz) {
suitableReaders.add(workerPair);
}
}
// Type -> MediaType.
typeToMediaTypeReadersCache.put(clazz, getMessageBodyWorkersMediaTypesByType(suitableReaders));
// Type -> Writer.
Collections.sort(suitableReaders, WORKER_BY_TYPE_COMPARATOR);
final List readers = Lists.newArrayList();
for (final MessageBodyWorkerPair workerPair : suitableReaders) {
readers.add(workerPair.provider);
}
mbrTypeLookupCache.put(clazz, readers);
}
@Override
@SuppressWarnings("unchecked")
public MediaType getMessageBodyWriterMediaType(Class> c, Type t,
Annotation[] as, List acceptableMediaTypes) {
for (MediaType acceptable : acceptableMediaTypes) {
for (MessageBodyWorkerPair mbwp : writers) {
for (MediaType mt : mbwp.types) {
if (mt.isCompatible(acceptable)
&& mbwp.provider.isWriteable(c, t, as, acceptable)) {
return MediaTypes.mostSpecific(mt, acceptable);
}
}
}
}
return null;
}
@Override
public Object readFrom(Class> rawType,
Type type,
Annotation[] annotations,
MediaType mediaType,
MultivaluedMap httpHeaders,
PropertiesDelegate propertiesDelegate,
InputStream entityStream,
Iterable readerInterceptors,
boolean translateNce) throws WebApplicationException, IOException {
ReaderInterceptorExecutor executor = new ReaderInterceptorExecutor(rawType, type, annotations, mediaType,
httpHeaders, propertiesDelegate, entityStream, this, readerInterceptors, translateNce);
return executor.proceed();
}
@Override
public OutputStream writeTo(Object t,
Class> rawType,
Type type,
Annotation[] annotations,
MediaType mediaType,
MultivaluedMap httpHeaders,
PropertiesDelegate propertiesDelegate,
OutputStream entityStream,
Iterable writerInterceptors)
throws IOException, WebApplicationException {
WriterInterceptorExecutor executor = new WriterInterceptorExecutor(t, rawType, type, annotations, mediaType,
httpHeaders, propertiesDelegate, entityStream, this, writerInterceptors);
executor.proceed();
return executor.getOutputStream();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy