Java tutorial
/******************************************************************************* * Copyright 2012 Eric McIntyre * * 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. ******************************************************************************/ package com.riversoforion.acheron.jaxb; import java.util.ArrayList; import java.util.List; import java.util.Map; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringUtils; import com.riversoforion.acheron.patterns.Builder; import com.riversoforion.acheron.patterns.CheckedExceptions; /** * Uses a Builder Pattern to construct a JAXBContext. The builder is populated with classes, properties, and other * attributes that will be used to initialize the context when the {@link #build() build} method is called. * * @author Eric McIntyre (<a href="mailto:mac@riversoforion.com">Mac</a>) */ public class JAXBContextBuilder implements Builder<JAXBContext> { private Class<?>[] boundClasses; private String contextPath; private ClassLoader classLoader; private Map<String, Object> props; private JAXBContext context; public JAXBContextBuilder() { } /** * Binds the classes with the specified names to the JAXBContext. Note that this method will have no effect if * {@link #forContextPath(String) contextPath} is not empty. * * @param boundClasses * A list of class names to bind. The class names will be resolved to class objects using the Thread's * context ClassLoader, or the one {@linkplain #withClassLoader(ClassLoader) configured for this builder} * . * @return This object */ public JAXBContextBuilder bindClasses(List<String> boundClasses) { this.boundClasses = resolveBoundClasses(boundClasses); return this; } /** * Binds the specified classes to the JAXBContext. Note that this method will have not effect if * {@link #forContextPath(String) contextPath} is not empty. * * @param boundClasses * The classes to bind. * @return This object */ public JAXBContextBuilder bindClasses(Class<?>... boundClasses) { this.boundClasses = boundClasses.clone(); return this; } /** * Uses the specified context path to resolve JAXB-annotated classes. * * @param contextPath * The package name that contains JAXB classes * @return This object */ public JAXBContextBuilder forContextPath(String contextPath) { this.contextPath = contextPath; return this; } /** * Uses the specified class loader to find and load classes that contain JAXB annotations. If this value is not set * the {@linkplain Thread#getContextClassLoader() thread's context ClassLoader} will be used. * * @param classLoader * The ClassLoader for resolving class references * @return This object */ public JAXBContextBuilder withClassLoader(ClassLoader classLoader) { this.classLoader = classLoader; return this; } /** * Sets the properties to use for configuring the JAXBContext. * * @param props * The properties to set when building the JAXBContext * @return This object */ public JAXBContextBuilder withProperties(Map<String, Object> props) { if (props != null) { this.props.putAll(props); } return this; } /** * Sets one property to use for configuring the JAXBContext. * * @param name * The name of the property to set. The recognized names are dependent on the JAXB implementation. * @param value * The value of the property. The acceptable values are dependent on the JAXB implementation and the * property being set. * @return This object */ public JAXBContextBuilder withProperty(String name, Object value) { this.props.put(name, value); return this; } /** * Builds the JAXBContext from the current values of this builder. If there is a {@link #forContextPath(String) * contextPath} set, the JAXBContext will be configured with that; otherwise, the set of specified classes will be * used. */ @Override public JAXBContext build() { if (!StringUtils.isEmpty(this.contextPath)) { buildWithContextPath(); } else if (!ArrayUtils.isEmpty(this.boundClasses)) { buildWithBoundClasses(); } else { throw new IllegalStateException("JAXB environment not configured properly"); } return current(); } @Override public JAXBContext current() { return this.context; } /** * Not implemented */ @Override public JAXBContextBuilder reset() { throw new UnsupportedOperationException("reset"); } private Class<?>[] resolveBoundClasses(List<String> classNames) { List<Class<?>> classObjects = new ArrayList<Class<?>>(); for (String className : classNames) { ClassLoader cl = getClassLoader(); try { Class<?> c = Class.forName(className, true, cl); classObjects.add(c); } catch (ClassNotFoundException e) { CheckedExceptions.throwAsUnchecked(e); } } return classObjects.toArray(new Class<?>[classObjects.size()]); } private void buildWithContextPath() { ClassLoader cl = getClassLoader(); try { this.context = JAXBContext.newInstance(this.contextPath, cl, this.props); } catch (JAXBException e) { CheckedExceptions.throwAsUnchecked(e); } } private void buildWithBoundClasses() { try { this.context = JAXBContext.newInstance(this.boundClasses, this.props); } catch (JAXBException e) { CheckedExceptions.throwAsUnchecked(e); } } private ClassLoader getClassLoader() { return this.classLoader != null ? this.classLoader : Thread.currentThread().getContextClassLoader(); } }