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.web.servlet.view.xml; 018 019import java.util.Map; 020 021import com.fasterxml.jackson.annotation.JsonView; 022import com.fasterxml.jackson.dataformat.xml.XmlMapper; 023 024import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; 025import org.springframework.validation.BindingResult; 026import org.springframework.web.servlet.View; 027import org.springframework.web.servlet.view.json.AbstractJackson2View; 028 029/** 030 * Spring MVC {@link View} that renders XML content by serializing the model for the current request 031 * using <a href="https://wiki.fasterxml.com/JacksonHome">Jackson 2's</a> {@link XmlMapper}. 032 * 033 * <p>The Object to be serialized is supplied as a parameter in the model. The first serializable 034 * entry is used. Users can either specify a specific entry in the model via the 035 * {@link #setModelKey(String) sourceKey} property. 036 * 037 * <p>The default constructor uses the default configuration provided by {@link Jackson2ObjectMapperBuilder}. 038 * 039 * <p>Compatible with Jackson 2.6 and higher, as of Spring 4.3. 040 * 041 * @author Sebastien Deleuze 042 * @since 4.1 043 * @see org.springframework.web.servlet.view.json.MappingJackson2JsonView 044 */ 045public class MappingJackson2XmlView extends AbstractJackson2View { 046 047 /** 048 * The default content type for the view. 049 */ 050 public static final String DEFAULT_CONTENT_TYPE = "application/xml"; 051 052 053 private String modelKey; 054 055 056 /** 057 * Construct a new {@code MappingJackson2XmlView} using default configuration 058 * provided by {@link Jackson2ObjectMapperBuilder} and setting the content type 059 * to {@code application/xml}. 060 */ 061 public MappingJackson2XmlView() { 062 super(Jackson2ObjectMapperBuilder.xml().build(), DEFAULT_CONTENT_TYPE); 063 } 064 065 /** 066 * Construct a new {@code MappingJackson2XmlView} using the provided {@link XmlMapper} 067 * and setting the content type to {@code application/xml}. 068 * @since 4.2.1 069 */ 070 public MappingJackson2XmlView(XmlMapper xmlMapper) { 071 super(xmlMapper, DEFAULT_CONTENT_TYPE); 072 } 073 074 075 @Override 076 public void setModelKey(String modelKey) { 077 this.modelKey = modelKey; 078 } 079 080 @Override 081 protected Object filterModel(Map<String, Object> model) { 082 Object value = null; 083 if (this.modelKey != null) { 084 value = model.get(this.modelKey); 085 if (value == null) { 086 throw new IllegalStateException( 087 "Model contains no object with key [" + this.modelKey + "]"); 088 } 089 } 090 else { 091 for (Map.Entry<String, Object> entry : model.entrySet()) { 092 if (!(entry.getValue() instanceof BindingResult) && !entry.getKey().equals(JsonView.class.getName())) { 093 if (value != null) { 094 throw new IllegalStateException("Model contains more than one object to render, only one is supported"); 095 } 096 value = entry.getValue(); 097 } 098 } 099 } 100 return value; 101 } 102 103}