001/* 002 * Copyright 2002-2019 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; 021 022import javax.xml.bind.JAXBContext; 023import javax.xml.bind.JAXBException; 024import javax.xml.bind.Marshaller; 025import javax.xml.bind.Unmarshaller; 026 027import org.springframework.http.converter.HttpMessageConversionException; 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 * @param <T> the converted object type 037 */ 038public abstract class AbstractJaxb2HttpMessageConverter<T> extends AbstractXmlHttpMessageConverter<T> { 039 040 private final ConcurrentMap<Class<?>, JAXBContext> jaxbContexts = new ConcurrentHashMap<>(64); 041 042 043 /** 044 * Create a new {@link Marshaller} for the given class. 045 * @param clazz the class to create the marshaller for 046 * @return the {@code Marshaller} 047 * @throws HttpMessageConversionException in case of JAXB errors 048 */ 049 protected final Marshaller createMarshaller(Class<?> clazz) { 050 try { 051 JAXBContext jaxbContext = getJaxbContext(clazz); 052 Marshaller marshaller = jaxbContext.createMarshaller(); 053 customizeMarshaller(marshaller); 054 return marshaller; 055 } 056 catch (JAXBException ex) { 057 throw new HttpMessageConversionException( 058 "Could not create Marshaller for class [" + clazz + "]: " + ex.getMessage(), ex); 059 } 060 } 061 062 /** 063 * Customize the {@link Marshaller} created by this 064 * message converter before using it to write the object to the output. 065 * @param marshaller the marshaller to customize 066 * @since 4.0.3 067 * @see #createMarshaller(Class) 068 */ 069 protected void customizeMarshaller(Marshaller marshaller) { 070 } 071 072 /** 073 * Create a new {@link Unmarshaller} for the given class. 074 * @param clazz the class to create the unmarshaller for 075 * @return the {@code Unmarshaller} 076 * @throws HttpMessageConversionException in case of JAXB errors 077 */ 078 protected final Unmarshaller createUnmarshaller(Class<?> clazz) { 079 try { 080 JAXBContext jaxbContext = getJaxbContext(clazz); 081 Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); 082 customizeUnmarshaller(unmarshaller); 083 return unmarshaller; 084 } 085 catch (JAXBException ex) { 086 throw new HttpMessageConversionException( 087 "Could not create Unmarshaller for class [" + clazz + "]: " + ex.getMessage(), ex); 088 } 089 } 090 091 /** 092 * Customize the {@link Unmarshaller} created by this 093 * message converter before using it to read the object from the input. 094 * @param unmarshaller the unmarshaller to customize 095 * @since 4.0.3 096 * @see #createUnmarshaller(Class) 097 */ 098 protected void customizeUnmarshaller(Unmarshaller unmarshaller) { 099 } 100 101 /** 102 * Return a {@link JAXBContext} for the given class. 103 * @param clazz the class to return the context for 104 * @return the {@code JAXBContext} 105 * @throws HttpMessageConversionException in case of JAXB errors 106 */ 107 protected final JAXBContext getJaxbContext(Class<?> clazz) { 108 return this.jaxbContexts.computeIfAbsent(clazz, key -> { 109 try { 110 return JAXBContext.newInstance(clazz); 111 } 112 catch (JAXBException ex) { 113 throw new HttpMessageConversionException( 114 "Could not create JAXBContext for class [" + clazz + "]: " + ex.getMessage(), ex); 115 } 116 }); 117 } 118 119}