/******************************************************************************* * Copyright (c) 2012-2016 Codenvy, S.A. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Codenvy, S.A. - initial API and implementation *******************************************************************************/ package org.everrest.core.impl.provider; import org.everrest.core.provider.EntityProvider; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.ws.rs.Consumes; import javax.ws.rs.Produces; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.ext.ContextResolver; import javax.ws.rs.ext.Provider; import javax.ws.rs.ext.Providers; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBElement; import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller; import javax.xml.bind.UnmarshalException; import javax.xml.transform.stream.StreamSource; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.lang.annotation.Annotation; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import static com.google.common.base.Strings.isNullOrEmpty; /** * @author andrew00x */ @Provider @Consumes({MediaType.APPLICATION_XML, "application/*+xml", MediaType.TEXT_XML, "text/*+xml"}) @Produces({MediaType.APPLICATION_XML, "application/*+xml", MediaType.TEXT_XML, "text/*+xml"}) public class JAXBElementEntityProvider implements EntityProvider<JAXBElement<?>> { /** Logger. */ private static final Logger LOG = LoggerFactory.getLogger(JAXBElementEntityProvider.class); /** @see Providers */ private Providers providers; public JAXBElementEntityProvider(@Context Providers providers) { this.providers = providers; } @Override public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) { return type == JAXBElement.class && genericType instanceof ParameterizedType; } @Override public JAXBElement<?> readFrom(Class<JAXBElement<?>> type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String, String> httpHeaders, InputStream entityStream) throws IOException { ParameterizedType parameterizedType = (ParameterizedType)genericType; Class<?> aClass = (Class<?>)parameterizedType.getActualTypeArguments()[0]; try { JAXBContext jaxbContext = getJAXBContext(aClass, mediaType); return jaxbContext.createUnmarshaller().unmarshal(new StreamSource(entityStream), aClass); } catch (UnmarshalException e) { LOG.debug(e.getMessage(), e); return null; } catch (JAXBException e) { throw new IOException(String.format("Can't read from input stream, %s", e)); } } @Override public long getSize(JAXBElement<?> t, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) { return -1; } @Override public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) { return JAXBElement.class.isAssignableFrom(type); } @Override public void writeTo(JAXBElement<?> t, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream) throws IOException { Class<?> declaredType = t.getDeclaredType(); try { JAXBContext jaxbContext = getJAXBContext(declaredType, mediaType); Marshaller marshaller = jaxbContext.createMarshaller(); String charset = getCharset(mediaType); if (!isNullOrEmpty(charset)) { marshaller.setProperty(Marshaller.JAXB_ENCODING, charset); } marshaller.marshal(t, entityStream); } catch (JAXBException e) { throw new IOException(String.format("Can't write to output stream, %s", e)); } } private String getCharset(MediaType mediaType) { return mediaType == null ? null : mediaType.getParameters().get("charset"); } /** * @param type * type * @param mediaType * media type * @return JAXBContext JAXBContext * @throws JAXBException * if JAXBContext creation failed */ protected JAXBContext getJAXBContext(Class<?> type, MediaType mediaType) throws JAXBException { ContextResolver<JAXBContextResolver> resolver = providers.getContextResolver(JAXBContextResolver.class, mediaType); if (resolver == null) { throw new RuntimeException(String.format("Not found any JAXBContextResolver for media type %s", mediaType)); } JAXBContextResolver jaxbContextResolver = resolver.getContext(null); return jaxbContextResolver.getJAXBContext(type); } }