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