001/* 002 * Copyright 2002-2018 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.http.converter.xml; 018 019import java.util.concurrent.ConcurrentHashMap; 020import java.util.concurrent.ConcurrentMap; 021import javax.xml.bind.JAXBContext; 022import javax.xml.bind.JAXBException; 023import javax.xml.bind.Marshaller; 024import javax.xml.bind.Unmarshaller; 025 026import org.springframework.http.converter.HttpMessageConversionException; 027import org.springframework.util.Assert; 028 029/** 030 * Abstract base class for {@link org.springframework.http.converter.HttpMessageConverter HttpMessageConverters} 031 * that use JAXB2. Creates {@link JAXBContext} object lazily. 032 * 033 * @author Arjen Poutsma 034 * @author Rossen Stoyanchev 035 * @since 3.0 036 */ 037public abstract class AbstractJaxb2HttpMessageConverter<T> extends AbstractXmlHttpMessageConverter<T> { 038 039 private final ConcurrentMap<Class<?>, JAXBContext> jaxbContexts = new ConcurrentHashMap<Class<?>, JAXBContext>(64); 040 041 042 /** 043 * Create a new {@link Marshaller} for the given class. 044 * @param clazz the class to create the marshaller for 045 * @return the {@code Marshaller} 046 * @throws HttpMessageConversionException in case of JAXB errors 047 */ 048 protected final Marshaller createMarshaller(Class<?> clazz) { 049 try { 050 JAXBContext jaxbContext = getJaxbContext(clazz); 051 Marshaller marshaller = jaxbContext.createMarshaller(); 052 customizeMarshaller(marshaller); 053 return marshaller; 054 } 055 catch (JAXBException ex) { 056 throw new HttpMessageConversionException( 057 "Could not create Marshaller for class [" + clazz + "]: " + ex.getMessage(), ex); 058 } 059 } 060 061 /** 062 * Customize the {@link Marshaller} created by this 063 * message converter before using it to write the object to the output. 064 * @param marshaller the marshaller to customize 065 * @since 4.0.3 066 * @see #createMarshaller(Class) 067 */ 068 protected void customizeMarshaller(Marshaller marshaller) { 069 } 070 071 /** 072 * Create a new {@link Unmarshaller} for the given class. 073 * @param clazz the class to create the unmarshaller for 074 * @return the {@code Unmarshaller} 075 * @throws HttpMessageConversionException in case of JAXB errors 076 */ 077 protected final Unmarshaller createUnmarshaller(Class<?> clazz) { 078 try { 079 JAXBContext jaxbContext = getJaxbContext(clazz); 080 Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); 081 customizeUnmarshaller(unmarshaller); 082 return unmarshaller; 083 } 084 catch (JAXBException ex) { 085 throw new HttpMessageConversionException( 086 "Could not create Unmarshaller for class [" + clazz + "]: " + ex.getMessage(), ex); 087 } 088 } 089 090 /** 091 * Customize the {@link Unmarshaller} created by this 092 * message converter before using it to read the object from the input. 093 * @param unmarshaller the unmarshaller to customize 094 * @since 4.0.3 095 * @see #createUnmarshaller(Class) 096 */ 097 protected void customizeUnmarshaller(Unmarshaller unmarshaller) { 098 } 099 100 /** 101 * Return a {@link JAXBContext} for the given class. 102 * @param clazz the class to return the context for 103 * @return the {@code JAXBContext} 104 * @throws HttpMessageConversionException in case of JAXB errors 105 */ 106 protected final JAXBContext getJaxbContext(Class<?> clazz) { 107 Assert.notNull(clazz, "Class must not be null"); 108 JAXBContext jaxbContext = this.jaxbContexts.get(clazz); 109 if (jaxbContext == null) { 110 try { 111 jaxbContext = JAXBContext.newInstance(clazz); 112 this.jaxbContexts.putIfAbsent(clazz, jaxbContext); 113 } 114 catch (JAXBException ex) { 115 throw new HttpMessageConversionException( 116 "Could not instantiate JAXBContext for class [" + clazz + "]: " + ex.getMessage(), ex); 117 } 118 } 119 return jaxbContext; 120 } 121 122}