gt:                 ref = marshallers.poll();
context: /**
   * Licensed to the Apache Software Foundation (ASF) under one
   * or more contributor license agreements. See the NOTICE file
   * distributed with this work for additional information
   * regarding copyright ownership. The ASF licenses this file
   * to you under the Apache License, Version 2.0 (the
   * "License"); you may not use this file except in compliance
   * with the License. You may obtain a copy of the License at
   *
   * http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing,
   * software distributed under the License is distributed on an
   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
   * KIND, either express or implied. See the License for the
   * specific language governing permissions and limitations
   * under the License.
   */
  
  package org.apache.cxf.jaxb;
  
  import java.io.IOException;
  import java.io.OutputStream;
  import java.lang.ref.SoftReference;
  import java.lang.reflect.Field;
  import java.lang.reflect.Method;
  import java.lang.reflect.ParameterizedType;
  import java.lang.reflect.Type;
  import java.net.URL;
  import java.util.ArrayList;
  import java.util.Arrays;
  import java.util.Collection;
  import java.util.Collections;
  import java.util.Deque;
  import java.util.HashMap;
  import java.util.HashSet;
  import java.util.LinkedHashSet;
  import java.util.List;
  import java.util.Map;
  import java.util.Set;
  import java.util.concurrent.LinkedBlockingDeque;
  import java.util.logging.Level;
  import java.util.logging.Logger;
  
  import javax.xml.bind.JAXBContext;
  import javax.xml.bind.JAXBElement;
  import javax.xml.bind.JAXBException;
  import javax.xml.bind.Marshaller;
  import javax.xml.bind.Unmarshaller;
  import javax.xml.bind.ValidationEventHandler;
  import javax.xml.bind.annotation.XmlElement;
  import javax.xml.namespace.QName;
  import javax.xml.stream.XMLEventReader;
  import javax.xml.stream.XMLEventWriter;
  import javax.xml.stream.XMLStreamReader;
  import javax.xml.stream.XMLStreamWriter;
  import javax.xml.transform.dom.DOMResult;
  import javax.xml.transform.dom.DOMSource;
  
  import org.w3c.dom.Document;
  import org.w3c.dom.Node;
  
  import org.xml.sax.InputSource;
  
  import org.apache.cxf.common.injection.NoJSR250Annotations;
  import org.apache.cxf.common.jaxb.JAXBContextCache;
  import org.apache.cxf.common.jaxb.JAXBContextCache.CachedContextAndSchemas;
  import org.apache.cxf.common.jaxb.JAXBUtils;
  import org.apache.cxf.common.logging.LogUtils;
  import org.apache.cxf.common.util.ModCountCopyOnWriteArrayList;
  import org.apache.cxf.common.util.PackageUtils;
  import org.apache.cxf.common.util.ReflectionUtil;
  import org.apache.cxf.common.xmlschema.SchemaCollection;
  import org.apache.cxf.databinding.AbstractDataBinding;
  import org.apache.cxf.databinding.AbstractWrapperHelper;
  import org.apache.cxf.databinding.DataReader;
  import org.apache.cxf.databinding.DataWriter;
  import org.apache.cxf.databinding.WrapperCapableDatabinding;
  import org.apache.cxf.databinding.WrapperHelper;
  import org.apache.cxf.interceptor.Interceptor;
  import org.apache.cxf.interceptor.InterceptorProvider;
  import org.apache.cxf.jaxb.attachment.JAXBAttachmentSchemaValidationHack;
  import org.apache.cxf.jaxb.io.DataReaderImpl;
  import org.apache.cxf.jaxb.io.DataWriterImpl;
  import org.apache.cxf.message.Message;
  import org.apache.cxf.resource.URIResolver;
  import org.apache.cxf.service.Service;
  import org.apache.cxf.service.factory.ReflectionServiceFactoryBean;
  import org.apache.cxf.service.factory.ServiceConstructionException;
  import org.apache.cxf.service.model.ServiceInfo;
  import org.apache.cxf.staxutils.StaxUtils;
  import org.apache.cxf.ws.addressing.ObjectFactory;
  
  @NoJSR250Annotations
  public class JAXBDataBinding extends AbstractDataBinding
      implements WrapperCapableDatabinding, InterceptorProvider {
  
      public static final String SCHEMA_RESOURCE = "SCHEMRESOURCE";
      public static final String MTOM_THRESHOLD = "org.apache.cxf.jaxb.mtomThreshold";
  
      public static final String UNWRAP_JAXB_ELEMENT = "unwrap.jaxb.element";
  
      public static final String USE_JAXB_BRIDGE = "use.jaxb.bridge";
  
      private static final Logger LOG = LogUtils.getLogger(JAXBDataBinding.class);
  
      private static final Class<?> SUPPORTED_READER_FORMATS[] = new Class<?>[] {Node.class,
                                                                                 XMLEventReader.class,
                                                                                 XMLStreamReader.class};
      private static final Class<?> SUPPORTED_WRITER_FORMATS[] = new Class<?>[] {OutputStream.class,
                                                                                 Node.class,
                                                                                 XMLEventWriter.class,
                                                                                 XMLStreamWriter.class};
      private static final boolean ENABLE_MARSHALL_POOLING = true;
      private static final boolean ENABLE_UNMARSHALL_POOLING = true;
      private static final int MAX_LOAD_FACTOR = 50;
  
      private static class DelayedDOMResult extends DOMResult {
          private final URL resource;
          private final String publicId;
          public DelayedDOMResult(URL url, String sysId, String pId) {
              super(null, sysId);
              resource = url;
              publicId = pId;
          }
          public synchronized Node getNode() {
              Node nd = super.getNode();
              if (nd == null) {
                  try {
                      InputSource src = new InputSource(resource.openStream());
                      src.setSystemId(this.getSystemId());
                      src.setPublicId(publicId);
                      Document doc = StaxUtils.read(src);
                      setNode(doc);
                      nd = super.getNode();
                  } catch (Exception ex) {
                      throw new RuntimeException(ex);
                  }
              }
              return nd;
          }
      }
      private static final Map<String, DOMResult> BUILT_IN_SCHEMAS = new HashMap<String, DOMResult>();
      static {
          URIResolver resolver = new URIResolver();
          try {
              resolver.resolve("", "classpath:/schemas/wsdl/ws-addr-wsdl.xsd", JAXBDataBinding.class);
              if (resolver.isResolved()) {
                  resolver.getInputStream().close();
                  DOMResult dr = new DelayedDOMResult(resolver.getURL(),
                                                      "classpath:/schemas/wsdl/ws-addr-wsdl.xsd",
                                                      "http://www.w3.org/2005/02/addressing/wsdl");
                  BUILT_IN_SCHEMAS.put("http://www.w3.org/2005/02/addressing/wsdl", dr);
                  resolver.unresolve();
              }
          } catch (Exception e) {
              //IGNORE
          }
          try {
              resolver.resolve("", "classpath:/schemas/wsdl/ws-addr.xsd", JAXBDataBinding.class);
              if (resolver.isResolved()) {
                  resolver.getInputStream().close();
                  DOMResult dr = new DelayedDOMResult(resolver.getURL(),
                                                      "classpath:/schemas/wsdl/ws-addr.xsd",
                                                      "http://www.w3.org/2005/08/addressing");
                  BUILT_IN_SCHEMAS.put("http://www.w3.org/2005/08/addressing", dr);
                  resolver.unresolve();
              }
          } catch (Exception e) {
              //IGNORE
          }
          try {
              resolver.resolve("", "classpath:/schemas/wsdl/wsrm.xsd", JAXBDataBinding.class);
              if (resolver.isResolved()) {
                  resolver.getInputStream().close();
                  DOMResult dr = new DelayedDOMResult(resolver.getURL(),
                                                      "classpath:/schemas/wsdl/wsrm.xsd",
                                                      "http://schemas.xmlsoap.org/ws/2005/02/rm");
                  BUILT_IN_SCHEMAS.put("http://schemas.xmlsoap.org/ws/2005/02/rm", dr);
                  resolver.unresolve();
              }
          } catch (Exception e) {
              //IGNORE
          }
      }
  
      Class<?>[] extraClass;
  
      JAXBContext context;
      Set<Class<?>> contextClasses;
      Collection<Object> typeRefs = new ArrayList<Object>();
  
      Class<?> cls;
  
      private Map<String, Object> contextProperties = Collections.emptyMap();
      private Map<String, Object> marshallerProperties = Collections.emptyMap();
      private Map<String, Object> unmarshallerProperties = Collections.emptyMap();
      private Unmarshaller.Listener unmarshallerListener;
      private Marshaller.Listener marshallerListener;
      private ValidationEventHandler validationEventHandler;
  
      private boolean unwrapJAXBElement = true;
  
      private boolean qualifiedSchemas;
  
      private ModCountCopyOnWriteArrayList<Interceptor<? extends Message>> in
          = new ModCountCopyOnWriteArrayList<Interceptor<? extends Message>>();
      private ModCountCopyOnWriteArrayList<Interceptor<? extends Message>> out
          = new ModCountCopyOnWriteArrayList<Interceptor<? extends Message>>();
      private ModCountCopyOnWriteArrayList<Interceptor<? extends Message>> outFault
          = new ModCountCopyOnWriteArrayList<Interceptor<? extends Message>>();
      private ModCountCopyOnWriteArrayList<Interceptor<? extends Message>> inFault
          = new ModCountCopyOnWriteArrayList<Interceptor<? extends Message>>();
  
      private Deque<SoftReference<Marshaller>> marshallers 
          = new LinkedBlockingDeque<SoftReference<Marshaller>>(MAX_LOAD_FACTOR);
      private Deque<SoftReference<Unmarshaller>> unmarshallers 
          = new LinkedBlockingDeque<SoftReference<Unmarshaller>>(MAX_LOAD_FACTOR);
  
      public JAXBDataBinding() {
      }
  
      public JAXBDataBinding(boolean q) {
          this.qualifiedSchemas = q;
      }
  
      public JAXBDataBinding(Class<?>... classes) throws JAXBException {
          contextClasses = new LinkedHashSet<Class<?>>();
          contextClasses.addAll(Arrays.asList(classes));
          setContext(createJAXBContext(contextClasses)); //NOPMD - specifically allow this
      }
      public JAXBDataBinding(ReflectionServiceFactoryBean b) throws JAXBException {
          this(b.isQualifyWrapperSchema());
          Map<String, Object> props = b.getProperties();
          if (props != null && props.get("jaxb.additionalContextClasses") != null) {
              Object o = b.getProperties().get("jaxb.additionalContextClasses");
              if (o instanceof Class) {
                  o = new Class[] {(Class<?>)o};
              }
              extraClass = (Class[])o;
          }
  
      }
  
      public JAXBDataBinding(JAXBContext context) {
          this();
          setContext(context);
      }
  
      public JAXBContext getContext() {
          return context;
      }
  
      public final void setContext(JAXBContext ctx) {
          context = ctx;
      }
  
      @SuppressWarnings("unchecked")
      public <T> DataWriter<T> createWriter(Class<T> c) {
  
          Integer mtomThresholdInt = new Integer(getMtomThreshold());
          if (c == XMLStreamWriter.class) {
              DataWriterImpl<XMLStreamWriter> r
                  = new DataWriterImpl<XMLStreamWriter>(this);
              r.setMtomThreshold(mtomThresholdInt);
              return (DataWriter<T>)r;
          } else if (c == OutputStream.class) {
              DataWriterImpl<OutputStream> r = new DataWriterImpl<OutputStream>(this);
              r.setMtomThreshold(mtomThresholdInt);
              return (DataWriter<T>)r;
          } else if (c == XMLEventWriter.class) {
              DataWriterImpl<XMLEventWriter> r = new DataWriterImpl<XMLEventWriter>(this);
              r.setMtomThreshold(mtomThresholdInt);
              return (DataWriter<T>)r;
          } else if (c == Node.class) {
              DataWriterImpl<Node> r = new DataWriterImpl<Node>(this);
              r.setMtomThreshold(mtomThresholdInt);
              return (DataWriter<T>)r;
          }
          return null;
      }
  
      public Class<?>[] getSupportedWriterFormats() {
          return SUPPORTED_WRITER_FORMATS;
      }
  
      @SuppressWarnings("unchecked")
      public <T> DataReader<T> createReader(Class<T> c) {
          DataReader<T> dr = null;
          if (c == XMLStreamReader.class) {
              dr = (DataReader<T>)new DataReaderImpl<XMLStreamReader>(this, unwrapJAXBElement);
          } else if (c == XMLEventReader.class) {
              dr = (DataReader<T>)new DataReaderImpl<XMLEventReader>(this, unwrapJAXBElement);
          } else if (c == Node.class) {
              dr = (DataReader<T>)new DataReaderImpl<Node>(this, unwrapJAXBElement);
          }
  
          return dr;
      }
  
      public Class<?>[] getSupportedReaderFormats() {
          return SUPPORTED_READER_FORMATS;
      }
  
      @SuppressWarnings("unchecked")
      public synchronized void initialize(Service service) {
  
          in.addIfAbsent(JAXBAttachmentSchemaValidationHack.INSTANCE);
          inFault.addIfAbsent(JAXBAttachmentSchemaValidationHack.INSTANCE);
  
          // context is already set, don't redo it
          if (context != null) {
              return;
          }
  
  
          contextClasses = new LinkedHashSet<Class<?>>();
          for (ServiceInfo serviceInfo : service.getServiceInfos()) {
              JAXBContextInitializer initializer
                  = new JAXBContextInitializer(serviceInfo, contextClasses, typeRefs);
              initializer.walk();
              if (serviceInfo.getProperty("extra.class") != null) {
                  Set<Class<?>> exClasses = serviceInfo.getProperty("extra.class", Set.class);
                  contextClasses.addAll(exClasses);
              }
  
          }
  
          String tns = getNamespaceToUse(service);
          CachedContextAndSchemas cachedContextAndSchemas = null;
          JAXBContext ctx = null;
          try {
              cachedContextAndSchemas = createJAXBContextAndSchemas(contextClasses, tns);
          } catch (JAXBException e1) {
              throw new ServiceConstructionException(e1);
          }
          ctx = cachedContextAndSchemas.getContext();
          if (LOG.isLoggable(Level.FINE)) {
              LOG.log(Level.FINE, "CREATED_JAXB_CONTEXT", new Object[] {ctx, contextClasses});
          }
          setContext(ctx);
  
          for (ServiceInfo serviceInfo : service.getServiceInfos()) {
              SchemaCollection col = serviceInfo.getXmlSchemaCollection();
  
              if (col.getXmlSchemas().length > 1) {
                  // someone has already filled in the types
                  continue;
              }
  
              boolean schemasFromCache = false;
              Collection<DOMSource> schemas = getSchemas();
              if (schemas == null || schemas.size() == 0) {
                  schemas = cachedContextAndSchemas.getSchemas();
                  if (schemas != null) {
                      schemasFromCache = true;
                  }
              } else {
                  schemasFromCache = true;
              }
              Set<DOMSource> bi = new LinkedHashSet<DOMSource>();
              if (schemas == null) {
                  schemas = new LinkedHashSet<DOMSource>();
                  try {
                      for (DOMResult r : generateJaxbSchemas()) {
                          DOMSource src = new DOMSource(r.getNode(), r.getSystemId());
                          if (BUILT_IN_SCHEMAS.containsValue(r)) {
                              bi.add(src);
                          } else {
                              schemas.add(src);
                          }
                      }
                      //put any builtins at the end.   Anything that DOES import them
                      //will cause it to load automatically and we'll skip them later
                      schemas.addAll(bi);
                  } catch (IOException e) {
                      throw new ServiceConstructionException("SCHEMA_GEN_EXC", LOG, e);
                  }
              }
              Set<String> ids = new HashSet<String>();
              for (DOMSource r : schemas) {
                  ids.add(r.getSystemId());
              }
              for (DOMSource r : schemas) {
                  if (bi.contains(r)) {
                      String ns = ((Document)r.getNode()).getDocumentElement().getAttribute("targetNamespace");
                      if (serviceInfo.getSchema(ns) != null) {
                          continue;
                      }
                  }
                  addSchemaDocument(serviceInfo,
                                    col,
                                   (Document)r.getNode(),
                                    r.getSystemId());
              }
  
              JAXBContext riContext;
              if (context.getClass().getName().contains("com.sun.xml.")) {
                  riContext = context;
              } else {
                  // fall back if we're using another jaxb implementation
                  try {
                      riContext = JAXBUtils.createRIContext(contextClasses
                          .toArray(new Class[contextClasses.size()]), tns);
                  } catch (JAXBException e) {
                      throw new ServiceConstructionException(e);
                  }
              }
  
              JAXBSchemaInitializer schemaInit = new JAXBSchemaInitializer(serviceInfo, col, riContext,
                                                                           this.qualifiedSchemas);
              schemaInit.walk();
              if (cachedContextAndSchemas != null && !schemasFromCache) {
                  cachedContextAndSchemas.setSchemas(schemas);
              }
          }
      }
  
      private String getNamespaceToUse(Service service) {
          if ("true".equals(service.get("org.apache.cxf.databinding.namespace"))) {
              return null;
          }
          String tns = null;
          if (service.getServiceInfos().size() > 0) {
              tns = service.getServiceInfos().get(0).getInterface().getName().getNamespaceURI();
          } else {
              tns = service.getName().getNamespaceURI();
          }
          return tns;
      }
  
      public void setExtraClass(Class<?>[] userExtraClass) {
          extraClass = userExtraClass;
      }
  
      public Class<?>[] getExtraClass() {
          return extraClass;
      }
  
      // default access for tests.
      List<DOMResult> generateJaxbSchemas() throws IOException {
          return JAXBUtils.generateJaxbSchemas(context, BUILT_IN_SCHEMAS);
      }
  
      public JAXBContext createJAXBContext(Set<Class<?>> classes) throws JAXBException {
          return createJAXBContext(classes, null);
      }
  
      public JAXBContext createJAXBContext(Set<Class<?>> classes, String defaultNs) throws JAXBException {
          return createJAXBContextAndSchemas(classes, defaultNs).getContext();
      }
  
      public CachedContextAndSchemas createJAXBContextAndSchemas(Set<Class<?>> classes,
                                                                 String defaultNs)
          throws JAXBException {
          //add user extra class into jaxb context
          if (extraClass != null && extraClass.length > 0) {
              for (Class<?> clz : extraClass) {
                  classes.add(clz);
              }
          }
          JAXBContextCache.scanPackages(classes);
          addWsAddressingTypes(classes);
  
          return JAXBContextCache.getCachedContextAndSchemas(classes, defaultNs,  
                                                            contextProperties, 
                                                            typeRefs, true);
  
      }
  
  
      private void addWsAddressingTypes(Set<Class<?>> classes) {
          if (classes.contains(ObjectFactory.class)) {
              // ws-addressing is used, lets add the specific types
              try {
                  classes.add(Class.forName("org.apache.cxf.ws.addressing.wsdl.ObjectFactory"));
                  classes.add(Class.forName("org.apache.cxf.ws.addressing.wsdl.AttributedQNameType"));
                  classes.add(Class.forName("org.apache.cxf.ws.addressing.wsdl.ServiceNameType"));
              } catch (ClassNotFoundException unused) {
                  // REVISIT - ignorable if WS-ADDRESSING not available?
                  // maybe add a way to allow interceptors to add stuff to the
                  // context?
              }
          }
      }
  
      public Set<Class<?>> getContextClasses() {
          return Collections.unmodifiableSet(this.contextClasses);
      }
  
      /**
       * Return a map of properties. These properties are passed to
       * JAXBContext.newInstance when this object creates a context.
       *
       * @return the map of JAXB context properties.
       */
      public Map<String, Object> getContextProperties() {
          return contextProperties;
      }
  
      /**
       * Set a map of JAXB context properties. These properties are passed to
       * JAXBContext.newInstance when this object creates a context. Note that if
       * you create a JAXB context elsewhere, you will not respect these
       * properties unless you handle it manually.
       *
       * @param contextProperties map of properties.
       */
      public void setContextProperties(Map<String, Object> contextProperties) {
          this.contextProperties = contextProperties;
      }
  
      /**
       * Return a map of properties. These properties are set into the JAXB
       * Marshaller (via Marshaller.setProperty(...) when the marshaller is
       * created.
       *
       * @return the map of JAXB marshaller properties.
       */
      public Map<String, Object> getMarshallerProperties() {
          return marshallerProperties;
      }
  
      /**
       * Set a map of JAXB marshaller properties. These properties are set into
       * the JAXB Marshaller (via Marshaller.setProperty(...) when the marshaller
       * is created.
       *
       * @param marshallerProperties map of properties.
       */
      public void setMarshallerProperties(Map<String, Object> marshallerProperties) {
          this.marshallerProperties = marshallerProperties;
      }
  
  
      /**
       * Return a map of properties. These properties are set into the JAXB
       * Unmarshaller (via Unmarshaller.setProperty(...) when the unmarshaller is
       * created.
       *
       * @return the map of JAXB unmarshaller properties.
       */
      public Map<String, Object> getUnmarshallerProperties() {
          return unmarshallerProperties;
      }
  
      /**
       * Set a map of JAXB unmarshaller properties. These properties are set into
       * the JAXB Unmarshaller (via Unmarshaller.setProperty(...) when the unmarshaller
       * is created.
       *
       * @param unmarshallerProperties map of properties.
       */
      public void setUnmarshallerProperties(Map<String, Object> unmarshallerProperties) {
          this.unmarshallerProperties = unmarshallerProperties;
      }
  
      /**
       * Returns the Unmarshaller.Listener that will be registered on the Unmarshallers
       * @return
       */
      public Unmarshaller.Listener getUnmarshallerListener() {
          return unmarshallerListener;
      }
  
      /**
       * Sets the Unmarshaller.Listener that will be registered on the Unmarshallers
       * @param unmarshallerListener
       */
      public void setUnmarshallerListener(Unmarshaller.Listener unmarshallerListener) {
          this.unmarshallerListener = unmarshallerListener;
      }
      /**
       * Returns the Marshaller.Listener that will be registered on the Marshallers
       * @return
       */
      public Marshaller.Listener getMarshallerListener() {
          return marshallerListener;
      }
  
      /**
       * Sets the Marshaller.Listener that will be registered on the Marshallers
       * @param marshallerListener
       */
      public void setMarshallerListener(Marshaller.Listener marshallerListener) {
          this.marshallerListener = marshallerListener;
      }
  
  
      public ValidationEventHandler getValidationEventHandler() {
          return validationEventHandler;
      }
  
      public void setValidationEventHandler(ValidationEventHandler validationEventHandler) {
          this.validationEventHandler = validationEventHandler;
      }
  
  
      public boolean isUnwrapJAXBElement() {
          return unwrapJAXBElement;
      }
  
      public void setUnwrapJAXBElement(boolean unwrapJAXBElement) {
          this.unwrapJAXBElement = unwrapJAXBElement;
      }
  
      public WrapperHelper createWrapperHelper(Class<?> wrapperType, QName wrapperName, List<String> partNames,
                                               List<String> elTypeNames, List<Class<?>> partClasses) {
          List<Method> getMethods = new ArrayList<Method>(partNames.size());
          List<Method> setMethods = new ArrayList<Method>(partNames.size());
          List<Method> jaxbMethods = new ArrayList<Method>(partNames.size());
          List<Field> fields = new ArrayList<Field>(partNames.size());
  
          Method allMethods[] = wrapperType.getMethods();
          String packageName = PackageUtils.getPackageName(wrapperType);
  
          //if wrappertype class is generated by ASM,getPackage() always return null
          if (wrapperType.getPackage() != null) {
              packageName = wrapperType.getPackage().getName();
          }
  
          String objectFactoryClassName = packageName + ".ObjectFactory";
  
          Object objectFactory = null;
          try {
              objectFactory = wrapperType.getClassLoader().loadClass(objectFactoryClassName).newInstance();
          } catch (Exception e) {
              //ignore, probably won't need it
          }
          Method allOFMethods[];
          if (objectFactory != null) {
              allOFMethods = objectFactory.getClass().getMethods();
          } else {
              allOFMethods = new Method[0];
          }
  
          for (int x = 0; x < partNames.size(); x++) {
              String partName = partNames.get(x);
              if (partName == null) {
                  getMethods.add(null);
                  setMethods.add(null);
                  fields.add(null);
                  jaxbMethods.add(null);
                  continue;
              }
  
              String elementType = elTypeNames.get(x);
  
              String getAccessor = JAXBUtils.nameToIdentifier(partName, JAXBUtils.IdentifierType.GETTER);
              String setAccessor = JAXBUtils.nameToIdentifier(partName, JAXBUtils.IdentifierType.SETTER);
              Method getMethod = null;
              Method setMethod = null;
              Class<?> valueClass = wrapperType;
  
              try {
                  getMethod = valueClass.getMethod(getAccessor, AbstractWrapperHelper.NO_CLASSES);
              } catch (NoSuchMethodException ex) {
                  //ignore for now
              }
  
              Field elField = getElField(partName, valueClass);
              if (getMethod == null
                  && elementType != null
                  && "boolean".equals(elementType.toLowerCase())
                  && (elField == null
                      || (!Collection.class.isAssignableFrom(elField.getType())
                      && !elField.getType().isArray()))) {
  
                  try {
                      String newAcc = getAccessor.replaceFirst("get", "is");
                      getMethod = wrapperType.getMethod(newAcc, AbstractWrapperHelper.NO_CLASSES);
                  } catch (NoSuchMethodException ex) {
                      //ignore for now
                  }
              }
              if (getMethod == null
                  && "return".equals(partName)) {
                  //RI generated code uses this
                  try {
                      getMethod = valueClass.getMethod("get_return", AbstractWrapperHelper.NO_CLASSES);
                  } catch (NoSuchMethodException ex) {
                      try {
                          getMethod = valueClass.getMethod("is_return",
                                                            new Class[0]);
                      } catch (NoSuchMethodException ex2) {
                          //ignore for now
                      }
                  }
              }
              if (getMethod == null && elField != null) {
                  getAccessor = JAXBUtils.nameToIdentifier(elField.getName(), JAXBUtils.IdentifierType.GETTER);
                  setAccessor = JAXBUtils.nameToIdentifier(elField.getName(), JAXBUtils.IdentifierType.SETTER);
                  try {
                      getMethod = valueClass.getMethod(getAccessor, AbstractWrapperHelper.NO_CLASSES);
                  } catch (NoSuchMethodException ex) {
                      //ignore for now
                  }
              }
              String setAccessor2 = setAccessor;
              if ("return".equals(partName)) {
                  //some versions of jaxb map "return" to "set_return" instead of "setReturn"
                  setAccessor2 = "set_return";
              }
  
              for (Method method : allMethods) {
                  if (method.getParameterTypes() != null && method.getParameterTypes().length == 1
                      && (setAccessor.equals(method.getName())
                          || setAccessor2.equals(method.getName()))) {
                      setMethod = method;
                      break;
                  }
              }
  
              getMethods.add(getMethod);
              setMethods.add(setMethod);
              if (setMethod != null
                  && JAXBElement.class.isAssignableFrom(setMethod.getParameterTypes()[0])) {
  
                  Type t = setMethod.getGenericParameterTypes()[0];
                  Class<?> pcls = null;
                  if (t instanceof ParameterizedType) {
                      t = ((ParameterizedType)t).getActualTypeArguments()[0];
                  }
                  if (t instanceof Class) {
                      pcls = (Class<?>)t;
                  }
  
                  String methodName = "create" + wrapperType.getSimpleName()
                      + setMethod.getName().substring(3);
  
                  for (Method m : allOFMethods) {
                      if (m.getName().equals(methodName)
                          && m.getParameterTypes().length == 1
                          && (pcls == null
                              || pcls.equals(m.getParameterTypes()[0]))) {
                          jaxbMethods.add(m);
                      }
                  }
              } else {
                  jaxbMethods.add(null);
              }
  
              if (elField != null) {
                  // JAXB Type get XmlElement Annotation
                  XmlElement el = elField.getAnnotation(XmlElement.class);
                  if (el != null
                      && (partName.equals(el.name())
                          || "##default".equals(el.name()))) {
                      ReflectionUtil.setAccessible(elField);
                      fields.add(elField);
                  } else {
                      if (getMethod == null && setMethod == null) {
                          if (el != null) {
                              LOG.warning("Could not create accessor for property " + partName
                                          + " of type " + wrapperType.getName() + " as the @XmlElement "
                                          + "defines the name as " + el.name());
                          } else {
                              LOG.warning("Could not create accessor for property " + partName
                                          + " of type " + wrapperType.getName());
                          }
                      }
                      fields.add(null);
                  }
              } else {
                  fields.add(null);
              }
  
          }
  
          return createWrapperHelper(wrapperType,
                                   setMethods.toArray(new Method[setMethods.size()]),
                                   getMethods.toArray(new Method[getMethods.size()]),
                                   jaxbMethods.toArray(new Method[jaxbMethods.size()]),
                                   fields.toArray(new Field[fields.size()]),
                                   objectFactory);
      }
  
      private static Field getElField(String partName, Class<?> wrapperType) {
          String fieldName = JAXBUtils.nameToIdentifier(partName, JAXBUtils.IdentifierType.VARIABLE);
          for (Field field : wrapperType.getDeclaredFields()) {
              XmlElement el = field.getAnnotation(XmlElement.class);
              if (el != null
                  && partName.equals(el.name())) {
                  return field;
              }
              if (field.getName().equals(fieldName)) {
                  return field;
              }
          }
          return null;
      }
  
  
      private static WrapperHelper createWrapperHelper(Class<?> wrapperType, Method setMethods[],
                                                       Method getMethods[], Method jaxbMethods[],
                                                       Field fields[], Object objectFactory) {
  
          WrapperHelper wh = compileWrapperHelper(wrapperType, setMethods, getMethods, jaxbMethods, fields,
                                                  objectFactory);
  
          if (wh == null) {
              wh = new JAXBWrapperHelper(wrapperType, setMethods, getMethods, jaxbMethods, fields,
                                         objectFactory);
          }
          return wh;
      }
  
      private static WrapperHelper compileWrapperHelper(Class<?> wrapperType, Method setMethods[],
                                                        Method getMethods[], Method jaxbMethods[],
                                                        Field fields[], Object objectFactory) {
          return WrapperHelperCompiler.compileWrapperHelper(wrapperType, setMethods, getMethods,
                                                            jaxbMethods, fields, objectFactory);
      }
  
      public List<Interceptor<? extends Message>> getOutFaultInterceptors() {
          return outFault;
      }
  
      public List<Interceptor<? extends Message>> getInFaultInterceptors() {
          return inFault;
      }
  
      public List<Interceptor<? extends Message>> getInInterceptors() {
          return in;
      }
  
      public List<Interceptor<? extends Message>> getOutInterceptors() {
          return out;
      }
    
      /**
       * releaseJAXBMarshalller
       * Do not call this method if an exception occurred while using the
       * Marshaller. We don't want an object in an invalid state.
       * 
       * @param marshaller Marshaller
       */
      public void releaseJAXBMarshaller(Marshaller marshaller) {
          if (ENABLE_MARSHALL_POOLING && marshaller != null) {
              marshallers.offerFirst(new SoftReference<Marshaller>(marshaller));
          }
      }    
  
      /**
       * Get JAXBMarshaller
       * 
       * @param context JAXBContext
       * @throws JAXBException
       */
      public Marshaller getJAXBMarshaller() throws JAXBException {
          Marshaller m = null;
  
          if (!ENABLE_MARSHALL_POOLING) {
              if (LOG.isLoggable(Level.FINE)) {
                  LOG.fine("Marshaller created [no pooling]");
              }
              m = getContext().createMarshaller();
          } else {
              SoftReference<Marshaller> ref = marshallers.poll();
              while (ref != null && ref.get() == null) {
  