class JAXBEncoderDecoder {

    public static Object unmarshall(Unmarshaller u,
                                    Object source,
                                    MessagePartInfo part,
                                    boolean unwrap) {
        Class<?> clazz = part != null ? part.getTypeClass() : null;
        if (clazz != null && Exception.class.isAssignableFrom(clazz)
            && Boolean.TRUE.equals(part.getProperty(JAXBDataBinding.class.getName() + ".CUSTOM_EXCEPTION"))) {
            return unmarshallException(u, source, part);
        }

        QName elName = part != null ? part.getConcreteName() : null;
        if (clazz != null && clazz.isArray()
            && part.getXmlSchema() instanceof XmlSchemaElement) {
            XmlSchemaElement el = (XmlSchemaElement)part.getXmlSchema();

            if (el.getSchemaType() instanceof XmlSchemaSimpleType
                && ((XmlSchemaSimpleType)el.getSchemaType()).getContent()
                instanceof XmlSchemaSimpleTypeList) {

                Object obj = unmarshall(u, source, elName, null, unwrap);
                if (clazz.isArray() && obj instanceof List) {
                    return ((List<?>)obj).toArray((Object[])Array.newInstance(clazz.getComponentType(),
                                                                           ((List<?>)obj).size()));
                }

                return obj;
            } else if (part.getMessageInfo().getOperation().isUnwrapped() && el.getMaxOccurs() != 1) {
                // must read ourselves....
                List<Object> ret = unmarshallArray(u, source, elName, clazz.getComponentType(),
                                                   createList(part));
                Object o = ret;
                if (!isList(part)) {
                    if (isSet(part)) {
                        o = createSet(part, ret);
                    } else if (clazz.getComponentType().isPrimitive()) {
                        o = java.lang.reflect.Array.newInstance(clazz.getComponentType(), ret.size());
                        for (int x = 0; x < ret.size(); x++) {
                            Array.set(o, x, ret.get(x));
                        }
                    } else {
                        o = ret.toArray((Object[])Array.newInstance(clazz.getComponentType(), ret.size()));
                    }
                }
                return o;
            }
        } else if (byte[].class == clazz && part.getTypeQName() != null
                   && "hexBinary".equals(part.getTypeQName().getLocalPart())) {

            String obj = (String)unmarshall(u, source, elName, String.class, unwrap);
            return new HexBinaryAdapter().unmarshal(obj);
        } else if (part != null && u.getSchema() != null
            && !(part.getXmlSchema() instanceof XmlSchemaElement)) {
            //Validating RPC/Lit, make sure we don't try a root element name thing
            source = updateSourceWithXSIType(source, part.getTypeQName());
        }

        Object o = unmarshall(u, source, elName, clazz, unwrap);
        if (o != null && o.getClass().isArray() && isList(part)) {
            List<Object> ret = createList(part);
            Collections.addAll(ret, (Object[])o);
            o = ret;
        }
        return o;
    }

    private  JAXBEncoderDecoder();

}