Package org.jboss.resteasy.plugins.providers.jaxb

Source Code of org.jboss.resteasy.plugins.providers.jaxb.JAXBXmlTypeProvider

/*
* JBoss, the OpenSource J2EE webOS Distributable under LGPL license. See terms of license at gnu.org.
*/
package org.jboss.resteasy.plugins.providers.jaxb;

import org.jboss.resteasy.annotations.providers.jaxb.DoNotUseJAXBProvider;
import org.jboss.resteasy.util.FindAnnotation;

import javax.ws.rs.Consumes;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.ext.Provider;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlRegistry;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Type;

/**
* <p>
* A JAXB entity provider that handles classes without {@link XmlRootElement} annotation. Classes which have
* been generated by XJC will most likely not contain this annotation, In order for these classes to
* marshalled, they must be wrapped within a {@link JAXBElement} instance. This is typically accomplished by
* invoking a method on the class which serves as the {@link XmlRegistry} and is named ObjectFactory.
* </p>
* <p>
* This provider is selected when the class is annotated with an {@link XmlType} annotation and
* <strong>not</strong> an {@link XmlRootElement} annotation.
* </p>
* <p>
* This provider simplifies this task by attempting to locate the {@link XmlRegistry} for the target class. By
* default, a JAXB implementation will create a class called ObjectFactory and is located in the same package
* as the target class. When this class is located, it will contain a "create" method that takes the object
* instance as a parameter. For example, of the target type is called "Contact", then the ObjectFactory class
* will have a method:
* </p>
* <code>
* public JAXBElement<Contact> createContact(Contact value);
* </code>
*
* @author <a href="ryan@damnhandy.com">Ryan J. McDonough</a>
* @version $Revision:$
*/
@Provider
@Produces("*/*")
@Consumes("*/*")
public class JAXBXmlTypeProvider extends AbstractJAXBProvider<Object>
{

   protected static final String OBJECT_FACTORY_NAME = ".ObjectFactory";

   /**
    *
    */
   @Override
   public void writeTo(Object t,
                       Class<?> type,
                       Type genericType,
                       Annotation[] annotations,
                       MediaType mediaType,
                       MultivaluedMap<String, Object> httpHeaders,
                       OutputStream entityStream) throws IOException
   {
      JAXBElement<?> result = wrapInJAXBElement(t, type);
      super.writeTo(result, type, genericType, annotations, mediaType, httpHeaders, entityStream);
   }

   @Override
   public Object readFrom(Class<Object> type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String, String> httpHeaders, InputStream entityStream) throws IOException
   {
      try
      {
         JAXBContext jaxb = findJAXBContext(type, annotations, mediaType, true);
         Unmarshaller unmarshaller = jaxb.createUnmarshaller();
         Object obj = unmarshaller.unmarshal(entityStream);
         if (obj instanceof JAXBElement)
         {
            JAXBElement element = (JAXBElement) obj;
            return element.getValue();

         }
         else
         {
            return obj;
         }
      }
      catch (JAXBException e)
      {
         throw new JAXBUnmarshalException(e);
      }
   }

   /**
    *
    */
   @Override
   protected boolean isReadWritable(Class<?> type,
                                    Type genericType,
                                    Annotation[] annotations,
                                    MediaType mediaType)
   {
      return (!type.isAnnotationPresent(XmlRootElement.class) && type.isAnnotationPresent(XmlType.class)) && (FindAnnotation.findAnnotation(type, annotations, DoNotUseJAXBProvider.class) == null) && !IgnoredMediaTypes.ignored(type, annotations, mediaType);
   }

   /**
    * Attempts to locate {@link XmlRegistry} for the XML type. Usually, a class named ObjectFactory is located
    * in the same package as the type we're trying to marshall. This method simply locates this class and
    * instantiates it if found.
    *
    * @param t
    * @param type
    * @return
    */
   public static Object findObjectFactory(Class<?> type)
   {
      try
      {
         Class<?> factoryClass = AbstractJAXBContextFinder.findDefaultObjectFactoryClass(type);
         if (factoryClass != null && factoryClass.isAnnotationPresent(XmlRegistry.class))
         {
            Object factory = factoryClass.newInstance();
            return factory;
         }
         else
         {
            throw new JAXBMarshalException("A valid XmlRegistry could not be located.");
         }
      }
      catch (InstantiationException e)
      {
         throw new JAXBMarshalException(e);
      }
      catch (IllegalAccessException e)
      {
         throw new JAXBMarshalException(e);
      }

   }

   /**
    * If this object is managed by an XmlRegistry, this method will invoke the registry and wrap the object in
    * a JAXBElement so that it can be marshalled.
    *
    * @param t
    * @param type
    * @return
    */
   public static JAXBElement<?> wrapInJAXBElement(Object t, Class<?> type)
   {
      try
      {
         Object factory = findObjectFactory(type);
         Method[] method = factory.getClass().getDeclaredMethods();
         for (int i = 0; i < method.length; i++)
         {
            Method current = method[i];
            if (current.getParameterTypes().length == 1 && current.getParameterTypes()[0].equals(type)
                    && current.getName().startsWith("create"))
            {
               Object result = current.invoke(factory, new Object[]
                       {t});
               return JAXBElement.class.cast(result);
            }
         }
         throw new JAXBMarshalException(String.format("The method create%s() "
                 + "was not found in the object Factory!", type));
      }
      catch (IllegalArgumentException e)
      {
         throw new JAXBMarshalException(e);
      }
      catch (IllegalAccessException e)
      {
         throw new JAXBMarshalException(e);
      }
      catch (InvocationTargetException e)
      {
         throw new JAXBMarshalException(e.getCause());
      }
   }
}
TOP

Related Classes of org.jboss.resteasy.plugins.providers.jaxb.JAXBXmlTypeProvider

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.