/*
* #%L
* Nazgul Project: nazgul-core-xmlbinding-spi-jaxb
* %%
* Copyright (C) 2010 - 2017 jGuru Europe AB
* %%
* Licensed under the jGuru Europe AB license (the "License"), based
* on Apache License, Version 2.0; you may not use this file except
* in compliance with the License.
*
* You may obtain a copy of the License at
*
* http://www.jguru.se/licenses/jguruCorporateSourceLicense-2.0.txt
*
* 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.
* #L%
*
*/
package se.jguru.nazgul.core.xmlbinding.spi.jaxb.transport;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import se.jguru.nazgul.core.algorithms.api.Validate;
import se.jguru.nazgul.core.reflection.api.conversion.ConverterRegistry;
import se.jguru.nazgul.core.reflection.api.conversion.registry.DefaultConverterRegistry;
import se.jguru.nazgul.core.xmlbinding.spi.jaxb.transport.converter.StandardConverters;
import se.jguru.nazgul.core.xmlbinding.spi.jaxb.transport.type.JaxbAnnotatedNull;
import javax.validation.constraints.NotNull;
import javax.xml.bind.annotation.XmlType;
import java.io.Serializable;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
/**
* Default JaxbConverterRegistry implementation, using reflection Converter
* instances to convert back and forth between JAXB-annotated transport types.
*
* @author <a href="mailto:lj@jguru.se">Lennart Jörelid</a>, jGuru Europe AB
*/
public class DefaultJaxbConverterRegistry implements JaxbConverterRegistry {
// Our Log
private static final Logger log = LoggerFactory.getLogger(DefaultJaxbConverterRegistry.class);
// Internal state
private static final List<? extends Class<? extends Serializable>> SELF_CONVERTIBLE =
Arrays.asList(Boolean.class, Byte.class, Short.class, Integer.class, Float.class,
Double.class, Long.class, String.class);
private ConverterRegistry registry;
/**
* Default constructor, creating a default ConverterRegistry to
* which most calls are delegated.
*/
public DefaultJaxbConverterRegistry() {
// Create internal state
registry = new DefaultConverterRegistry();
// Add the standard converters
addConverters(new StandardConverters());
}
/**
* {@inheritDoc}
*/
@Override
public final void addConverters(final Object... converters) throws IllegalArgumentException {
registry.add(converters);
}
/**
* {@inheritDoc}
*/
@Override
public <TransportType, OriginalType> Class<TransportType> getTransportType(
@NotNull final Class<OriginalType> originalType) {
// Check sanity
Validate.notNull(originalType, "originalType");
// If the OriginalType is annotated with @XmlType, simply return it.
if (originalType.isAnnotationPresent(XmlType.class)) {
return (Class<TransportType>) originalType;
}
// Find something in our registry?
final Set<Class<?>> possibleConversions = registry.getPossibleConversions(originalType);
for (Class<?> current : possibleConversions) {
// Is this a transport type?
// Also, disregard the JaxbAnnotatedNull in fuzzy logic searches.
if (!(current.equals(JaxbAnnotatedNull.class))
&& current.isAnnotationPresent(XmlType.class)) {
return (Class<TransportType>) current;
}
}
// No converter found.
log.debug("No converter found for [" + originalType.getSimpleName() + "]. PossibleConversions: ["
+ possibleConversions + "], registry: " + registry);
return null;
}
/**
* {@inheritDoc}
*/
@Override
public <OriginalType, TransportType> Class<OriginalType> getOriginalType(
@NotNull final Class<TransportType> transportType) throws IllegalArgumentException {
// Check sanity
Validate.notNull(transportType, "transportType");
Validate.isTrue(transportType != JaxbAnnotatedNull.class,
"Cannot acquire OriginalType for JaxbAnnotatedNull argument.");
// If the transportType is neither a Primitive nor annotated with XmlType ... complain.
boolean incorrectType = !transportType.isPrimitive()
&& !SELF_CONVERTIBLE.contains(transportType)
&& !transportType.isAnnotationPresent(XmlType.class);
if (incorrectType) {
throw new IllegalArgumentException("Supplied transportType [" + transportType.getName()
+ "] is not annotated with XmlType.");
}
// Find something in our registry?
for (Class<?> current : registry.getPossibleConversions(transportType)) {
// Is this a non-transport type?
if (!current.isAnnotationPresent(XmlType.class)) {
return (Class<OriginalType>) current;
}
}
// None found.
return null;
}
/**
* {@inheritDoc}
*/
@Override
public <OriginalType, TransportType> TransportType packageForTransport(final OriginalType source)
throws IllegalArgumentException {
// Null values --> JaxbAnnotatedNull
if (source == null) {
return (TransportType) JaxbAnnotatedNull.getInstance();
}
// Find the transport type of the source.
final Class<TransportType> transportTypeClass = getTransportType(source.getClass());
TransportType toReturn = (TransportType) source;
if (transportTypeClass != null) {
// Convert the source instance to the supplied transportClass (or a subclass).
toReturn = registry.convert(source, transportTypeClass);
}
// All done
return toReturn;
}
/**
* {@inheritDoc}
*/
@Override
public <OriginalType, TransportType> OriginalType resurrectAfterTransport(final TransportType transport)
throws IllegalArgumentException {
// No null values are accepted here (since they must have been converted
// into JaxbAnnotatedNull instances).
Validate.notNull(transport, "Cannot resurrect null transportType instance.");
// Handle actual null cases
if (transport instanceof JaxbAnnotatedNull) {
return null;
}
// Find the original type of the transport
final Class<OriginalType> originalType = getOriginalType(transport.getClass());
// All done
return originalType == null ? (OriginalType) transport : registry.convert(transport, originalType);
}
/**
* {@inheritDoc}
*/
@Override
public String toString() {
return "DefaultJaxbConverterRegistry with internal state: " + this.registry;
}
}