Provide a flag to disable XML support

This commit introduces a spring.xml.ignore system property
which when set to true avoid initializing XML infrastructure.

A typical use case is optimizing GraalVM native image footprint
for applications not using XML. In order to be effective, those
classes should be initialized at build time:

- org.springframework.util.DefaultPropertiesPersister
- org.springframework.core.io.support.PropertiesLoaderUtils
- org.springframework.web.servlet.function.support.RouterFunctionMapping
- org.springframework.web.client.RestTemplate
- org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver
- org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport
- org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
- org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter
- org.springframework.http.codec.support.BaseDefaultCodecs
- org.springframework.beans.PropertyEditorRegistrySupport

Closes gh-25151
This commit is contained in:
Sébastien Deleuze
2020-06-19 08:54:21 +02:00
parent ce728a6c4b
commit 1e501f2583
10 changed files with 184 additions and 55 deletions

View File

@@ -21,6 +21,7 @@ import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.springframework.core.SpringProperties;
import org.springframework.core.codec.AbstractDataBufferDecoder;
import org.springframework.core.codec.ByteArrayDecoder;
import org.springframework.core.codec.ByteArrayEncoder;
@@ -70,6 +71,13 @@ import org.springframework.util.ClassUtils;
*/
class BaseDefaultCodecs implements CodecConfigurer.DefaultCodecs, CodecConfigurer.DefaultCodecConfig {
/**
* Boolean flag controlled by a {@code spring.xml.ignore} system property that instructs Spring to
* ignore XML, i.e. to not initialize the XML-related infrastructure.
* <p>The default is "false".
*/
private static final boolean shouldIgnoreXml = SpringProperties.getFlag("spring.xml.ignore");
static final boolean jackson2Present;
private static final boolean jackson2SmilePresent;
@@ -284,7 +292,7 @@ class BaseDefaultCodecs implements CodecConfigurer.DefaultCodecs, CodecConfigure
((AbstractJackson2Decoder) codec).setMaxInMemorySize(size);
}
}
if (jaxb2Present) {
if (jaxb2Present && !shouldIgnoreXml) {
if (codec instanceof Jaxb2XmlDecoder) {
((Jaxb2XmlDecoder) codec).setMaxInMemorySize(size);
}
@@ -353,7 +361,7 @@ class BaseDefaultCodecs implements CodecConfigurer.DefaultCodecs, CodecConfigure
addCodec(readers, new DecoderHttpMessageReader<>(this.jackson2SmileDecoder != null ?
(Jackson2SmileDecoder) this.jackson2SmileDecoder : new Jackson2SmileDecoder()));
}
if (jaxb2Present) {
if (jaxb2Present && !shouldIgnoreXml) {
addCodec(readers, new DecoderHttpMessageReader<>(this.jaxb2Decoder != null ?
(Jaxb2XmlDecoder) this.jaxb2Decoder : new Jaxb2XmlDecoder()));
}
@@ -449,7 +457,7 @@ class BaseDefaultCodecs implements CodecConfigurer.DefaultCodecs, CodecConfigure
writers.add(new EncoderHttpMessageWriter<>(this.jackson2SmileEncoder != null ?
(Jackson2SmileEncoder) this.jackson2SmileEncoder : new Jackson2SmileEncoder()));
}
if (jaxb2Present) {
if (jaxb2Present && !shouldIgnoreXml) {
writers.add(new EncoderHttpMessageWriter<>(this.jaxb2Encoder != null ?
(Jaxb2XmlEncoder) this.jaxb2Encoder : new Jaxb2XmlEncoder()));
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2020 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.
@@ -16,6 +16,7 @@
package org.springframework.http.converter.support;
import org.springframework.core.SpringProperties;
import org.springframework.http.converter.FormHttpMessageConverter;
import org.springframework.http.converter.json.GsonHttpMessageConverter;
import org.springframework.http.converter.json.JsonbHttpMessageConverter;
@@ -32,10 +33,18 @@ import org.springframework.util.ClassUtils;
*
* @author Rossen Stoyanchev
* @author Juergen Hoeller
* @author Sebastien Deleuze
* @since 3.2
*/
public class AllEncompassingFormHttpMessageConverter extends FormHttpMessageConverter {
/**
* Boolean flag controlled by a {@code spring.xml.ignore} system property that instructs Spring to
* ignore XML, i.e. to not initialize the XML-related infrastructure.
* <p>The default is "false".
*/
private static final boolean shouldIgnoreXml = SpringProperties.getFlag("spring.xml.ignore");
private static final boolean jaxb2Present;
private static final boolean jackson2Present;
@@ -61,15 +70,17 @@ public class AllEncompassingFormHttpMessageConverter extends FormHttpMessageConv
public AllEncompassingFormHttpMessageConverter() {
try {
addPartConverter(new SourceHttpMessageConverter<>());
}
catch (Error err) {
// Ignore when no TransformerFactory implementation is available
}
if (!shouldIgnoreXml) {
try {
addPartConverter(new SourceHttpMessageConverter<>());
}
catch (Error err) {
// Ignore when no TransformerFactory implementation is available
}
if (jaxb2Present && !jackson2XmlPresent) {
addPartConverter(new Jaxb2RootElementHttpMessageConverter());
if (jaxb2Present) {
addPartConverter(new Jaxb2RootElementHttpMessageConverter());
}
}
if (jackson2Present) {
@@ -82,7 +93,7 @@ public class AllEncompassingFormHttpMessageConverter extends FormHttpMessageConv
addPartConverter(new JsonbHttpMessageConverter());
}
if (jackson2XmlPresent) {
if (jackson2XmlPresent && !shouldIgnoreXml) {
addPartConverter(new MappingJackson2XmlHttpMessageConverter());
}

View File

@@ -29,6 +29,7 @@ import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.core.SpringProperties;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
@@ -82,6 +83,7 @@ import org.springframework.web.util.UriTemplateHandler;
* @author Roy Clarkson
* @author Juergen Hoeller
* @author Sam Brannen
* @author Sebastien Deleuze
* @since 3.0
* @see HttpMessageConverter
* @see RequestCallback
@@ -90,6 +92,13 @@ import org.springframework.web.util.UriTemplateHandler;
*/
public class RestTemplate extends InterceptingHttpAccessor implements RestOperations {
/**
* Boolean flag controlled by a {@code spring.xml.ignore} system property that instructs Spring to
* ignore XML, i.e. to not initialize the XML-related infrastructure.
* <p>The default is "false".
*/
private static final boolean shouldIgnoreXml = SpringProperties.getFlag("spring.xml.ignore");
private static final boolean romePresent;
private static final boolean jaxb2Present;
@@ -138,11 +147,13 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat
this.messageConverters.add(new ByteArrayHttpMessageConverter());
this.messageConverters.add(new StringHttpMessageConverter());
this.messageConverters.add(new ResourceHttpMessageConverter(false));
try {
this.messageConverters.add(new SourceHttpMessageConverter<>());
}
catch (Error err) {
// Ignore when no TransformerFactory implementation is available
if (!shouldIgnoreXml) {
try {
this.messageConverters.add(new SourceHttpMessageConverter<>());
}
catch (Error err) {
// Ignore when no TransformerFactory implementation is available
}
}
this.messageConverters.add(new AllEncompassingFormHttpMessageConverter());
@@ -151,11 +162,13 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat
this.messageConverters.add(new RssChannelHttpMessageConverter());
}
if (jackson2XmlPresent) {
this.messageConverters.add(new MappingJackson2XmlHttpMessageConverter());
}
else if (jaxb2Present) {
this.messageConverters.add(new Jaxb2RootElementHttpMessageConverter());
if (!shouldIgnoreXml) {
if (jackson2XmlPresent) {
this.messageConverters.add(new MappingJackson2XmlHttpMessageConverter());
}
else if (jaxb2Present) {
this.messageConverters.add(new Jaxb2RootElementHttpMessageConverter());
}
}
if (jackson2Present) {