package io.eguan.vold.rest.resources; /* * #%L * Project eguan * %% * Copyright (C) 2012 - 2017 Oodrive * %% * Licensed 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. * #L% */ import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.concurrent.GuardedBy; 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.XmlRootElement; import javax.xml.bind.annotation.XmlType; import javax.xml.bind.util.JAXBSource; import javax.xml.namespace.QName; import com.google.common.base.Strings; /** * Replicator for JAXB-annotated POJOs. * * This replicator only managed one class that must be annotated with either {@link XmlRootElement} or {@link XmlType}. * * @author oodrive * @author pwehrle * * @param <T> * the JAXB-annotated POJO class to manage */ public final class JaxbPojoReplicator<T extends Object> { private final Class<T> targetClass; private volatile Boolean initialized = Boolean.FALSE; @GuardedBy("initialized") private QName qName; @GuardedBy("initialized") private JAXBContext context; @GuardedBy("initialized") private Unmarshaller unmarshaller; /** * Constructs a replicator for instances of the given class. * * @param targetClass * the */ public JaxbPojoReplicator(@Nonnull final Class<T> targetClass) { this.targetClass = Objects.requireNonNull(targetClass); } /** * Initializes the JAXB context classes needed for (de-)serialization-based replication. * * @throws JAXBException * if initialization fails */ public final void init() throws JAXBException { synchronized (initialized) { context = JAXBContext.newInstance(targetClass); unmarshaller = context.createUnmarshaller(); final XmlRootElement rootAnnotation = targetClass.getAnnotation(XmlRootElement.class); if ((rootAnnotation != null) && (!Strings.isNullOrEmpty(rootAnnotation.name()))) { this.qName = new QName(rootAnnotation.name()); } else { final XmlType typeAnnotation = targetClass.getAnnotation(XmlType.class); if ((typeAnnotation == null) || (Strings.isNullOrEmpty(typeAnnotation.name()))) { throw new IllegalStateException("No QName found for " + targetClass); } this.qName = new QName(typeAnnotation.name()); } initialized = Boolean.TRUE; } } /** * Returns this instance to a uninitialized state. */ public final void fini() { synchronized (initialized) { qName = null; unmarshaller = null; context = null; initialized = Boolean.FALSE; } } /** * Attempts to replicate the provided instance using JAXB (de-)serialization. * * @param original * the instance to replicate * @return an independent copy of the bean * @throws JAXBException * if (de-)serialization fails */ public T replicate(final T original) throws JAXBException { if (!initialized) { init(); } synchronized (initialized) { final JAXBElement<T> vvrElem = new JAXBElement<>(qName, targetClass, original); final JAXBSource vvrSource = new JAXBSource(context, vvrElem); return unmarshaller.unmarshal(vvrSource, targetClass).getValue(); } } }