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.oxm.support; 018 019import java.io.IOException; 020 021import javax.xml.transform.Source; 022import javax.xml.transform.sax.SAXResult; 023import javax.xml.transform.sax.SAXSource; 024 025import org.xml.sax.ContentHandler; 026import org.xml.sax.DTDHandler; 027import org.xml.sax.EntityResolver; 028import org.xml.sax.ErrorHandler; 029import org.xml.sax.InputSource; 030import org.xml.sax.SAXException; 031import org.xml.sax.SAXNotRecognizedException; 032import org.xml.sax.SAXParseException; 033import org.xml.sax.XMLReader; 034import org.xml.sax.ext.LexicalHandler; 035 036import org.springframework.lang.Nullable; 037import org.springframework.oxm.Marshaller; 038import org.springframework.util.Assert; 039 040/** 041 * {@link Source} implementation that uses a {@link Marshaller}.Can be constructed with a 042 * {@code Marshaller} and an object to be marshalled. 043 * 044 * <p>Even though {@code MarshallingSource} extends from {@code SAXSource}, calling the methods of 045 * {@code SAXSource} is <strong>not supported</strong>. In general, the only supported operation on this class is 046 * to use the {@code XMLReader} obtained via {@link #getXMLReader()} to parse the input source obtained via {@link 047 * #getInputSource()}. Calling {@link #setXMLReader(XMLReader)} or {@link #setInputSource(InputSource)} will result in 048 * {@code UnsupportedOperationException}s. 049 * 050 * @author Arjen Poutsma 051 * @since 3.0 052 * @see javax.xml.transform.Transformer 053 */ 054public class MarshallingSource extends SAXSource { 055 056 private final Marshaller marshaller; 057 058 private final Object content; 059 060 061 /** 062 * Create a new {@code MarshallingSource} with the given marshaller and content. 063 * @param marshaller the marshaller to use 064 * @param content the object to be marshalled 065 */ 066 public MarshallingSource(Marshaller marshaller, Object content) { 067 super(new MarshallingXMLReader(marshaller, content), new InputSource()); 068 Assert.notNull(marshaller, "'marshaller' must not be null"); 069 Assert.notNull(content, "'content' must not be null"); 070 this.marshaller = marshaller; 071 this.content = content; 072 } 073 074 075 /** 076 * Return the {@code Marshaller} used by this {@code MarshallingSource}. 077 */ 078 public Marshaller getMarshaller() { 079 return this.marshaller; 080 } 081 082 /** 083 * Return the object to be marshalled. 084 */ 085 public Object getContent() { 086 return this.content; 087 } 088 089 /** 090 * Throws a {@code UnsupportedOperationException}. 091 */ 092 @Override 093 public void setInputSource(InputSource inputSource) { 094 throw new UnsupportedOperationException("setInputSource is not supported"); 095 } 096 097 /** 098 * Throws a {@code UnsupportedOperationException}. 099 */ 100 @Override 101 public void setXMLReader(XMLReader reader) { 102 throw new UnsupportedOperationException("setXMLReader is not supported"); 103 } 104 105 106 private static final class MarshallingXMLReader implements XMLReader { 107 108 private final Marshaller marshaller; 109 110 private final Object content; 111 112 @Nullable 113 private DTDHandler dtdHandler; 114 115 @Nullable 116 private ContentHandler contentHandler; 117 118 @Nullable 119 private EntityResolver entityResolver; 120 121 @Nullable 122 private ErrorHandler errorHandler; 123 124 @Nullable 125 private LexicalHandler lexicalHandler; 126 127 private MarshallingXMLReader(Marshaller marshaller, Object content) { 128 Assert.notNull(marshaller, "'marshaller' must not be null"); 129 Assert.notNull(content, "'content' must not be null"); 130 this.marshaller = marshaller; 131 this.content = content; 132 } 133 134 @Override 135 public void setContentHandler(@Nullable ContentHandler contentHandler) { 136 this.contentHandler = contentHandler; 137 } 138 139 @Override 140 @Nullable 141 public ContentHandler getContentHandler() { 142 return this.contentHandler; 143 } 144 145 @Override 146 public void setDTDHandler(@Nullable DTDHandler dtdHandler) { 147 this.dtdHandler = dtdHandler; 148 } 149 150 @Override 151 @Nullable 152 public DTDHandler getDTDHandler() { 153 return this.dtdHandler; 154 } 155 156 @Override 157 public void setEntityResolver(@Nullable EntityResolver entityResolver) { 158 this.entityResolver = entityResolver; 159 } 160 161 @Override 162 @Nullable 163 public EntityResolver getEntityResolver() { 164 return this.entityResolver; 165 } 166 167 @Override 168 public void setErrorHandler(@Nullable ErrorHandler errorHandler) { 169 this.errorHandler = errorHandler; 170 } 171 172 @Override 173 @Nullable 174 public ErrorHandler getErrorHandler() { 175 return this.errorHandler; 176 } 177 178 @Nullable 179 protected LexicalHandler getLexicalHandler() { 180 return this.lexicalHandler; 181 } 182 183 @Override 184 public boolean getFeature(String name) throws SAXNotRecognizedException { 185 throw new SAXNotRecognizedException(name); 186 } 187 188 @Override 189 public void setFeature(String name, boolean value) throws SAXNotRecognizedException { 190 throw new SAXNotRecognizedException(name); 191 } 192 193 @Override 194 @Nullable 195 public Object getProperty(String name) throws SAXNotRecognizedException { 196 if ("http://xml.org/sax/properties/lexical-handler".equals(name)) { 197 return this.lexicalHandler; 198 } 199 else { 200 throw new SAXNotRecognizedException(name); 201 } 202 } 203 204 @Override 205 public void setProperty(String name, Object value) throws SAXNotRecognizedException { 206 if ("http://xml.org/sax/properties/lexical-handler".equals(name)) { 207 this.lexicalHandler = (LexicalHandler) value; 208 } 209 else { 210 throw new SAXNotRecognizedException(name); 211 } 212 } 213 214 @Override 215 public void parse(InputSource input) throws SAXException { 216 parse(); 217 } 218 219 @Override 220 public void parse(String systemId) throws SAXException { 221 parse(); 222 } 223 224 private void parse() throws SAXException { 225 SAXResult result = new SAXResult(getContentHandler()); 226 result.setLexicalHandler(getLexicalHandler()); 227 try { 228 this.marshaller.marshal(this.content, result); 229 } 230 catch (IOException ex) { 231 SAXParseException saxException = new SAXParseException(ex.getMessage(), null, null, -1, -1, ex); 232 ErrorHandler errorHandler = getErrorHandler(); 233 if (errorHandler != null) { 234 errorHandler.fatalError(saxException); 235 } 236 else { 237 throw saxException; 238 } 239 } 240 } 241 } 242 243}