Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
grails.converters.XML Maven / Gradle / Ivy
/*
* Copyright 2006-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package grails.converters;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Writer;
import java.util.List;
import java.util.Map;
import java.util.Stack;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import groovy.lang.Closure;
import groovy.util.BuilderSupport;
import groovy.xml.slurpersupport.GPathResult;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.util.Assert;
import grails.core.support.proxy.EntityProxyHandler;
import grails.core.support.proxy.ProxyHandler;
import grails.util.GrailsNameUtils;
import grails.util.GrailsWebUtil;
import grails.web.mime.MimeType;
import org.grails.buffer.FastStringWriter;
import org.grails.io.support.SpringIOUtils;
import org.grails.web.converters.AbstractConverter;
import org.grails.web.converters.Converter;
import org.grails.web.converters.ConverterUtil;
import org.grails.web.converters.IncludeExcludeConverter;
import org.grails.web.converters.configuration.ConverterConfiguration;
import org.grails.web.converters.configuration.ConvertersConfigurationHolder;
import org.grails.web.converters.configuration.DefaultConverterConfiguration;
import org.grails.web.converters.exceptions.ConverterException;
import org.grails.web.converters.marshaller.ClosureObjectMarshaller;
import org.grails.web.converters.marshaller.NameAwareMarshaller;
import org.grails.web.converters.marshaller.ObjectMarshaller;
import org.grails.web.xml.PrettyPrintXMLStreamWriter;
import org.grails.web.xml.StreamingMarkupWriter;
import org.grails.web.xml.XMLStreamWriter;
/**
* A converter that converts domain classes to XML.
*
* @author Siegfried Puchbauer
* @author Graeme Rocher
*/
public class XML extends AbstractConverter implements IncludeExcludeConverter {
public static final Log log = LogFactory.getLog(XML.class);
private static final String CACHED_XML = "org.codehaus.groovy.grails.CACHED_XML_REQUEST_CONTENT";
private Object target;
private StreamingMarkupWriter stream;
private final ConverterConfiguration config;
private final String encoding;
private final CircularReferenceBehaviour circularReferenceBehaviour;
private XMLStreamWriter writer;
private final Stack referenceStack = new Stack<>();
private boolean isRendering = false;
public XML() {
this.config = ConvertersConfigurationHolder.getConverterConfiguration(XML.class);
this.encoding = this.config.getEncoding() != null ? this.config.getEncoding() : "UTF-8";
contentType = MimeType.XML.getName();
this.circularReferenceBehaviour = this.config.getCircularReferenceBehaviour();
}
public XML(Object target) {
this();
this.target = target;
}
public XML(XMLStreamWriter writer) {
this();
this.writer = writer;
this.isRendering = true;
}
protected ConverterConfiguration initConfig() {
return ConvertersConfigurationHolder.getConverterConfiguration(XML.class);
}
@Override
public void setTarget(Object target) {
this.target = target;
}
private void finalizeRender(Writer out) {
try {
if (out != null) {
out.flush();
out.close();
}
}
catch (Exception e) {
log.warn("Unexpected exception while closing a writer: " + e.getMessage());
}
}
public void render(Writer out) throws ConverterException {
this.stream = new StreamingMarkupWriter(out, this.encoding);
this.writer = this.config.isPrettyPrint() ? new PrettyPrintXMLStreamWriter(this.stream) : new XMLStreamWriter(this.stream);
try {
this.isRendering = true;
this.writer.startDocument(this.encoding, "1.0");
this.writer.startNode(getElementName(this.target));
convertAnother(this.target);
this.writer.end();
finalizeRender(out);
}
catch (Exception e) {
throw new ConverterException(e);
}
finally {
this.isRendering = false;
}
}
private void checkState() {
Assert.state(this.isRendering, "Illegal XML Converter call!");
}
public String getElementName(Object o) {
ObjectMarshaller om = this.config.getMarshaller(o);
if (om instanceof NameAwareMarshaller) {
return ((NameAwareMarshaller) om).getElementName(o);
}
ProxyHandler proxyHandler = this.config.getProxyHandler();
if (proxyHandler.isProxy(o) && (proxyHandler instanceof EntityProxyHandler)) {
EntityProxyHandler entityProxyHandler = (EntityProxyHandler) proxyHandler;
Class> cls = entityProxyHandler.getProxiedClass(o);
return GrailsNameUtils.getPropertyName(cls);
}
return GrailsNameUtils.getPropertyName(o.getClass());
}
public void convertAnother(Object o) throws ConverterException {
o = this.config.getProxyHandler().unwrapIfProxy(o);
try {
if (o == null) {
// noop
}
else if (o instanceof CharSequence) {
this.writer.characters(o.toString());
}
else if (o instanceof Class>) {
this.writer.characters(((Class>) o).getName());
}
else if ((o.getClass().isPrimitive() && !o.getClass().equals(byte[].class)) ||
o instanceof Number || o instanceof Boolean) {
this.writer.characters(String.valueOf(o));
}
else {
if (this.referenceStack.contains(o)) {
handleCircularRelationship(o);
}
else {
this.referenceStack.push(o);
ObjectMarshaller marshaller = this.config.getMarshaller(o);
if (marshaller == null) {
throw new ConverterException("Unconvertable Object of class: " + o.getClass().getName());
}
marshaller.marshalObject(o, this);
this.referenceStack.pop();
}
}
}
catch (Throwable t) {
throw ConverterUtil.resolveConverterException(t);
}
}
public ObjectMarshaller lookupObjectMarshaller(Object target) {
return this.config.getMarshaller(target);
}
public int getDepth() {
return this.referenceStack.size();
}
public XML startNode(String tagName) {
checkState();
try {
this.writer.startNode(tagName);
}
catch (Exception e) {
throw ConverterUtil.resolveConverterException(e);
}
return this;
}
public XML chars(String chars) {
checkState();
try {
this.writer.characters(chars);
}
catch (Exception e) {
throw ConverterUtil.resolveConverterException(e);
}
return this;
}
public XML attribute(String name, String value) {
checkState();
try {
this.writer.attribute(name, value);
}
catch (Exception e) {
throw ConverterUtil.resolveConverterException(e);
}
return this;
}
public XML end() {
checkState();
try {
this.writer.end();
}
catch (Exception e) {
throw ConverterUtil.resolveConverterException(e);
}
return this;
}
@SuppressWarnings("incomplete-switch")
protected void handleCircularRelationship(Object o) throws ConverterException {
switch (this.circularReferenceBehaviour) {
case DEFAULT:
StringBuilder ref = new StringBuilder();
int idx = this.referenceStack.indexOf(o);
for (int i = this.referenceStack.size() - 1; i > idx; i--) {
ref.append("../");
}
attribute("ref", ref.substring(0, ref.length() - 1));
break;
case EXCEPTION:
throw new ConverterException("Circular Reference detected: class " + o.getClass().getName());
case INSERT_NULL:
convertAnother(null);
}
}
public void render(HttpServletResponse response) throws ConverterException {
response.setContentType(GrailsWebUtil.getContentType(contentType, this.encoding));
try {
render(response.getWriter());
}
catch (IOException e) {
throw new ConverterException(e);
}
}
public XMLStreamWriter getWriter() throws ConverterException {
checkState();
return this.writer;
}
public StreamingMarkupWriter getStream() {
checkState();
return this.stream;
}
public void build(@SuppressWarnings("rawtypes") Closure c) throws ConverterException {
// checkState();
// chars("");
// StreamingMarkupBuilder smb = new StreamingMarkupBuilder();
// Writable writable = (Writable) smb.bind(c);
// try {
// writable.writeTo(getStream().unescaped());
// }
// catch (IOException e) {
// throw new ConverterException(e);
// }
new Builder(this).execute(c);
}
@Override
public String toString() {
FastStringWriter strw = new FastStringWriter();
render(strw);
strw.flush();
return strw.toString();
}
/**
* Parses the given XML
*
* @param source a String containing some XML
* @return a groovy.xml.XmlSlurper
* @throws ConverterException
*/
public static GPathResult parse(String source) throws ConverterException {
try {
return SpringIOUtils.createXmlSlurper().parseText(source);
}
catch (Exception e) {
throw new ConverterException("Error parsing XML", e);
}
}
/**
* Parses the given XML
*
* @param is an InputStream to read from
* @param encoding the Character Encoding to use
* @return a groovy.xml.XmlSlurper
* @throws ConverterException
*/
public static GPathResult parse(InputStream is, String encoding) throws ConverterException {
try {
InputStreamReader reader = new InputStreamReader(is, encoding);
return SpringIOUtils.createXmlSlurper().parse(reader);
}
catch (Exception e) {
throw new ConverterException("Error parsing XML", e);
}
}
/**
* Parses the give XML (read from the POST Body of the Request)
*
* @param request an HttpServletRequest
* @return a groovy.xml.XmlSlurper
* @throws ConverterException
*/
public static Object parse(HttpServletRequest request) throws ConverterException {
Object xml = request.getAttribute(CACHED_XML);
if (xml != null) {
return xml;
}
String encoding = request.getCharacterEncoding();
if (encoding == null) {
encoding = Converter.DEFAULT_REQUEST_ENCODING;
}
try {
if (!request.getMethod().equalsIgnoreCase("GET")) {
xml = parse(request.getInputStream(), encoding);
request.setAttribute(CACHED_XML, xml);
}
return xml;
}
catch (IOException e) {
throw new ConverterException("Error parsing XML", e);
}
}
public static ConverterConfiguration getNamedConfig(String configName) throws ConverterException {
ConverterConfiguration cfg = ConvertersConfigurationHolder.getNamedConverterConfiguration(
configName, XML.class);
if (cfg == null) {
throw new ConverterException(String.format("Converter Configuration with name '%s' not found!", configName));
}
return cfg;
}
public static Object use(String configName, Closure> callable) throws ConverterException {
ConverterConfiguration old = ConvertersConfigurationHolder.getThreadLocalConverterConfiguration(XML.class);
ConverterConfiguration cfg = getNamedConfig(configName);
ConvertersConfigurationHolder.setThreadLocalConverterConfiguration(XML.class, cfg);
try {
return callable.call();
}
finally {
ConvertersConfigurationHolder.setThreadLocalConverterConfiguration(XML.class, old);
}
}
public static void use(String cfgName) throws ConverterException {
if (cfgName == null || "default".equals(cfgName)) {
ConvertersConfigurationHolder.setThreadLocalConverterConfiguration(XML.class, null);
}
else {
ConvertersConfigurationHolder.setThreadLocalConverterConfiguration(XML.class, getNamedConfig(cfgName));
}
}
public static void registerObjectMarshaller(Class> clazz, Closure> callable) throws ConverterException {
registerObjectMarshaller(new ClosureObjectMarshaller<>(clazz, callable));
}
public static void registerObjectMarshaller(Class> clazz, int priority, Closure> callable) throws ConverterException {
registerObjectMarshaller(new ClosureObjectMarshaller<>(clazz, callable), priority);
}
public static void registerObjectMarshaller(ObjectMarshaller om) throws ConverterException {
ConverterConfiguration cfg = ConvertersConfigurationHolder.getConverterConfiguration(XML.class);
if (cfg == null) {
throw new ConverterException("Default Configuration not found for class " + XML.class.getName());
}
if (!(cfg instanceof DefaultConverterConfiguration>)) {
cfg = new DefaultConverterConfiguration<>(cfg);
ConvertersConfigurationHolder.setDefaultConfiguration(XML.class, cfg);
}
((DefaultConverterConfiguration) cfg).registerObjectMarshaller(om);
}
public static void registerObjectMarshaller(ObjectMarshaller om, int priority) throws ConverterException {
ConverterConfiguration cfg = ConvertersConfigurationHolder.getConverterConfiguration(XML.class);
if (cfg == null) {
throw new ConverterException("Default Configuration not found for class " + XML.class.getName());
}
if (!(cfg instanceof DefaultConverterConfiguration>)) {
cfg = new DefaultConverterConfiguration<>(cfg);
ConvertersConfigurationHolder.setDefaultConfiguration(XML.class, cfg);
}
((DefaultConverterConfiguration) cfg).registerObjectMarshaller(om, priority);
}
public static void createNamedConfig(String name, Closure> callable) throws ConverterException {
DefaultConverterConfiguration cfg =
new DefaultConverterConfiguration<>(ConvertersConfigurationHolder.getConverterConfiguration(XML.class));
try {
callable.call(cfg);
ConvertersConfigurationHolder.setNamedConverterConfiguration(XML.class, name, cfg);
}
catch (Exception e) {
throw ConverterUtil.resolveConverterException(e);
}
}
public static void withDefaultConfiguration(Closure> callable) throws ConverterException {
ConverterConfiguration cfg = ConvertersConfigurationHolder.getConverterConfiguration(XML.class);
if (!(cfg instanceof DefaultConverterConfiguration>)) {
cfg = new DefaultConverterConfiguration<>(cfg);
}
try {
callable.call(cfg);
ConvertersConfigurationHolder.setDefaultConfiguration(XML.class, cfg);
}
catch (Throwable t) {
throw ConverterUtil.resolveConverterException(t);
}
}
@Override
public void setIncludes(List includes) {
setIncludes(this.target.getClass(), includes);
}
@Override
public void setExcludes(List excludes) {
setExcludes(this.target.getClass(), excludes);
}
public class Builder extends BuilderSupport {
private XML xml;
public Builder(XML xml) {
this.xml = xml;
}
public void execute(Closure> callable) {
callable.setDelegate(this);
callable.call();
}
@Override
protected Object createNode(Object name) {
return createNode(name, null, null);
}
@Override
protected Object createNode(Object name, Object value) {
return createNode(name, null, value);
}
@SuppressWarnings("rawtypes")
@Override
protected Object createNode(Object name, Map attributes) {
return createNode(name, attributes, null);
}
@SuppressWarnings("rawtypes")
@Override
protected Object createNode(Object name, Map attributes, Object value) {
this.xml.startNode(name.toString());
if (attributes != null) {
for (Object o : attributes.entrySet()) {
Map.Entry attribute = (Map.Entry) o;
this.xml.attribute(attribute.getKey().toString(), attribute.getValue().toString());
}
}
if (value != null) {
this.xml.convertAnother(value);
}
return name;
}
@Override
protected void nodeCompleted(Object o, Object o1) {
this.xml.end();
}
@Override
protected void setParent(Object o, Object o1) {
// do nothing
}
}
}