Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat!: Update to Spring 6, Boot 3 #13545

Merged
merged 20 commits into from
Jul 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
4a34451
feat(spring6)!: Move from javax.servlet to jakarta.servlet
matrei Jul 11, 2024
425112d
chore: Update license headers
matrei Jul 11, 2024
3064d74
fix(spring6): Simplify BeanCreationProfilingPostProcessor
matrei Jul 10, 2024
666942f
fix(spring6): Remove deprecated OptimizedAutowireCapableBeanFactory
matrei Jul 10, 2024
0f4ff9e
fix(spring6): Remove grails-web-fileupload project
matrei Jul 11, 2024
fab2c0f
fix(spring6): Deprecate MockHttpServletResponse
matrei Jul 11, 2024
cbc4157
fix(spring6): Replace removed NestedIOException
matrei Jul 11, 2024
6467f81
fix(spring6): Add missing classes for annotation reading
matrei Jul 11, 2024
f0719bd
fix(spring6): Config loads correctly to Spring profiles
matrei Jul 12, 2024
82ea455
test: Set `@PendingFeature` on tests that uses `grails-plugin-convert…
matrei Jul 12, 2024
8a274e0
test: Disable tests using `grails-gsp`
matrei Jul 12, 2024
ed70c1e
test: Change Spring profile property in test config
matrei Jul 12, 2024
6779052
fix(deps): Update Spring to 6.0.22
matrei Jul 12, 2024
c6505df
fix(deps): Update Tomcat to 10.1.25
matrei Jul 12, 2024
9da5c94
fix(deps): Update Spring Boot to 3.1.12
matrei Jul 12, 2024
4c4a02c
feat!: Update to and compatible with Spring 6.1, Boot 3.2
matrei Jul 12, 2024
bd7b7d6
test(deps): Remove unused test dependencies
matrei Jul 15, 2024
a0ca114
feat!(deps): Update to and compatible with Micronaut 4.5
matrei Jul 16, 2024
fb05a15
chore(deps): Remove unused test dependencies
matrei Jul 17, 2024
3b868c7
docs: Add javadoc explaining that classes are ported from Spring
matrei Jul 17, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -446,7 +446,7 @@ subprojects { project ->

if (project.name =~ /^(grails-web|grails-plugin-|grails-test-suite|grails-test)/) {
dependencies {
api "javax.servlet:javax.servlet-api:$servletApiVersion"
api "jakarta.servlet:jakarta.servlet-api:$servletApiVersion"
// MockHttpServletRequest/Response/Context used in many classes
api("org.springframework:spring-test:${springVersion}") {
exclude group: 'commons-logging', module: 'commons-logging'
Expand Down
17 changes: 9 additions & 8 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ groovyVersion=4.0.22
gspVersion=6.2.1
h2.version=2.2.224
h2Version=2.2.224
jacksonVersion=2.17.2
hibernateDatastoreVersion=8.1.0
jakartaAnnotationApiVersion=2.0.0
jansiVersion=2.4.1
Expand All @@ -28,24 +29,24 @@ junitVersion=4.13.2
logbackVersion=1.2.7
legacyConvertersVersion=5.0.0
methvinDirectoryWatcherVersion=0.18.0
micronautCacheVersion=3.5.0
micronautRuntimeGroovyVersion=3.4.0
micronautSpringVersion=4.5.1
micronautVersion=3.10.4
micronautCacheVersion=4.3.0
micronautRuntimeGroovyVersion=4.3.0
micronautSpringVersion=5.7.0
micronautVersion=4.5.3
mongodbJavaDriverVersion=4.11.0
objenesisVersion=3.3
scaffoldingCoreVersion=2.1.0
servletApiVersion=4.0.1
servletApiVersion=6.0.0
slf4jVersion=1.7.36
snakeyamlVersion=2.2
spockVersion=2.3-groovy-4.0
springBootVersion=2.7.18
springBootVersion=3.2.6
matrei marked this conversation as resolved.
Show resolved Hide resolved
springLoadedVersion=1.2.8.RELEASE
springVersion=5.3.33
springVersion=6.1.8
testingSupportVersion=3.2.1
testingSupportVersionForTests=3.2.2
tomcatLog4jVersion=8.5.2
tomcatVersion=9.0.87
tomcatVersion=10.1.25
viewsVersion=3.2.3
org.gradle.caching=true
org.gradle.parallel=true
Expand Down
2 changes: 1 addition & 1 deletion grails-bootstrap/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import org.apache.tools.ant.filters.ReplaceTokens
dependencies {
api ( "org.apache.groovy:groovy-xml:$groovyVersion" )
api ( "org.apache.groovy:groovy-templates:$groovyVersion" )
api "org.yaml:snakeyaml"
api "org.yaml:snakeyaml:$snakeyamlVersion"
api "io.micronaut:micronaut-inject:$micronautVersion"

compileOnly("io.methvin:directory-watcher:$methvinDirectoryWatcherVersion")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,23 @@
/*
* Copyright 2014-2024 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 org.grails.config

import groovy.transform.CompileDynamic
import groovy.transform.CompileStatic
import groovy.transform.EqualsAndHashCode
import org.codehaus.groovy.runtime.DefaultGroovyMethods
import org.slf4j.Logger
import org.slf4j.LoggerFactory

Expand All @@ -22,6 +36,9 @@ class NavigableMap implements Map<String, Object>, Cloneable {
private static final Pattern SPLIT_PATTERN = ~/\./
private static final String SPRING_PROFILES = 'spring.profiles.active'
private static final String SPRING = 'spring'
private static final String CONFIG = 'config'
private static final String ACTIVATE = 'activate'
private static final String ON_PROFILE = 'on-profile'
private static final String PROFILES = 'profiles'
private static final String SUBSCRIPT_REGEX = /((.*)\[(\d+)\]).*/

Expand Down Expand Up @@ -136,6 +153,11 @@ class NavigableMap implements Map<String, Object>, Cloneable {
NavigableMap targetMap,
Map sourceMap,
boolean parseFlatKeys) {

if(springProfileExclude(sourceMap, path)) {
return
}

for (Entry entry in sourceMap) {
Object sourceKeyObject = entry.key
Object sourceValue = entry.value
Expand All @@ -157,13 +179,52 @@ class NavigableMap implements Map<String, Object>, Cloneable {
}
}

private boolean shouldSkipBlock(Map sourceMap, String path) {
Object springProfileDefined = System.properties.getProperty(SPRING_PROFILES)
boolean hasSpringProfiles =
sourceMap.get(SPRING) instanceof Map && ((Map)sourceMap.get(SPRING)).get(PROFILES) ||
path == SPRING && sourceMap.get(PROFILES)
private static boolean springProfileExclude(Map sourceMap, String path) {

// Is there an active Spring profile?
def activeSpringProfile = System.getProperty(SPRING_PROFILES)

// Is there a 'spring.config.activate.on-profile' property defined in the source map?
def sourceMapProfile1 = ((Map)((Map)((Map)sourceMap?.get(SPRING))?.get(CONFIG))?.get(ACTIVATE))?.get(ON_PROFILE)
if (!sourceMapProfile1 && path == "$SPRING.$CONFIG.$ACTIVATE") {
sourceMapProfile1 = sourceMap?.get(ON_PROFILE)
}
if (!sourceMapProfile1) {
sourceMapProfile1 = sourceMap.get("$SPRING.$CONFIG.$ACTIVATE.$ON_PROFILE" as String)
}
if (sourceMapProfile1 && !activeSpringProfile) {
// There is a spring.config.activate.on-profile property defined in this sourceMap, but there is no active spring profile
return true
}
if (sourceMapProfile1 == activeSpringProfile) {
// The active spring profile matches the spring.config.activate.on-profile property in this sourceMap
return false
}

// Is there a 'spring.profiles' property defined in the source map? (Old way of Spring profiles activation)
def sourceMapProfile2 = ((Map)sourceMap?.get(SPRING))?.get(PROFILES)
if (!sourceMapProfile2 && path == SPRING) {
sourceMapProfile2 = sourceMap?.get(PROFILES)
}
if (!sourceMapProfile2) {
sourceMapProfile2 = sourceMap.get("$SPRING.$PROFILES" as String)
}
if (sourceMapProfile1 && !activeSpringProfile) {
// There is a spring.config.activate.on-profile property defined in this sourceMap, but there is no active spring profile
return true
}
if (sourceMapProfile2 == activeSpringProfile) {
// The active spring profile matches the spring.profiles property in this sourceMap
return false
}

if (activeSpringProfile && !sourceMapProfile1 && !sourceMapProfile2) {
// There is no spring profile defined in this sourceMap, it should always be included
return false
}

return !springProfileDefined && hasSpringProfiles
// We can skip this sourceMap as it defines a spring profile that is not active
return true
}

protected void mergeMapEntry(NavigableMap rootMap, String path, NavigableMap targetMap, String sourceKey, Object sourceValue, boolean parseFlatKeys, boolean isNestedSet = false) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
/*
* Copyright 2011 SpringSource
* Copyright 2011-2024 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* 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,
Expand Down Expand Up @@ -49,7 +49,7 @@ public class DefaultStackTraceFilterer implements StackTraceFilterer {
"org.springframework.boot.devtools.",
"org.springsource.loaded.",
"com.opensymphony.",
"javax.servlet."
"jakarta.servlet."
};

private List<String> packagesToFilter = new ArrayList<String>();
Expand Down
2 changes: 1 addition & 1 deletion grails-console/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,5 @@ dependencies {

api "org.springframework:spring-web:${springVersion}"

api "javax.servlet:javax.servlet-api:$servletApiVersion"
api "jakarta.servlet:jakarta.servlet-api:$servletApiVersion"
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
/*
* Copyright 2014 original authors
* Copyright 2014-2024 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* 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,
Expand Down Expand Up @@ -49,7 +49,7 @@ class GrailsSwingConsole extends GrailsApp {
}

void configureApplicationContextClass() {
if (ClassUtils.isPresent("javax.servlet.ServletContext", Thread.currentThread().contextClassLoader)) {
if (ClassUtils.isPresent("jakarta.servlet.ServletContext", Thread.currentThread().contextClassLoader)) {
setApplicationContextFactory(ApplicationContextFactory.ofContextClass(GroovyConsoleWebApplicationContext))
} else {
setApplicationContextFactory(ApplicationContextFactory.ofContextClass(GroovyConsoleApplicationContext))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
/*
* Copyright 2014 original authors
* Copyright 2014-2024 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* 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,
Expand Down Expand Up @@ -44,7 +44,7 @@ class GrailsShell extends GrailsApp {
}

public configureApplicationContextClass() {
if (ClassUtils.isPresent("javax.servlet.ServletContext", Thread.currentThread().contextClassLoader)) {
if (ClassUtils.isPresent("jakarta.servlet.ServletContext", Thread.currentThread().contextClassLoader)) {
setApplicationContextFactory(ApplicationContextFactory.ofContextClass(GroovyshWebApplicationContext))
} else {
setApplicationContextFactory(ApplicationContextFactory.ofContextClass(GroovyshApplicationContext))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
/*
* Copyright 2014 original authors
* Copyright 2014-2024 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* 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,
Expand Down Expand Up @@ -35,7 +35,7 @@ class DevelopmentGrailsApplication extends GrailsApp {
}

protected configureApplicationContextClass() {
if (ClassUtils.isPresent("javax.servlet.ServletContext", Thread.currentThread().contextClassLoader)) {
if (ClassUtils.isPresent("jakarta.servlet.ServletContext", Thread.currentThread().contextClassLoader)) {
setApplicationContextFactory(ApplicationContextFactory.ofContextClass(DevelopmentWebApplicationContext))
} else {
setApplicationContextFactory(ApplicationContextFactory.ofContextClass(GenericWebApplicationContext))
Expand Down
1 change: 1 addition & 0 deletions grails-core/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ dependencies {
testImplementation "org.hamcrest:hamcrest-core:1.3"

testRuntimeOnly "com.h2database:h2:$h2Version"
testRuntimeOnly "com.fasterxml.jackson.core:jackson-databind:$jacksonVersion"

// These dependencies are not required, but due to a Groovy compiler bug they are loaded by Groovy and hence
// have to be on the path for compilation even though they shouldn't be
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
/*
* Copyright 2002-2024 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 org.grails.asm;

import java.lang.reflect.Field;
import java.security.AccessControlException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.springframework.asm.AnnotationVisitor;
import org.springframework.asm.SpringAsmInfo;
import org.springframework.asm.Type;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.lang.Nullable;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;

/**
* {@link AnnotationVisitor} to recursively visit annotations.

* <p>Note: This class was ported to Grails 7 from Spring Framework 5.3 as it was
* removed in Spring 6 without a public replacement.
*
* @author Chris Beams
* @author Juergen Hoeller
* @author Phillip Webb
* @author Sam Brannen
* @since 3.1.1
* @deprecated As of Spring Framework 5.2, this class and related classes in this
* package have been replaced by SimpleAnnotationMetadataReadingVisitor
* and related classes for internal use within the framework.
*/
@Deprecated
abstract class AbstractRecursiveAnnotationVisitor extends AnnotationVisitor {

protected final Log logger = LogFactory.getLog(getClass());

protected final AnnotationAttributes attributes;

@Nullable
protected final ClassLoader classLoader;


public AbstractRecursiveAnnotationVisitor(@Nullable ClassLoader classLoader, AnnotationAttributes attributes) {
super(SpringAsmInfo.ASM_VERSION);
this.classLoader = classLoader;
this.attributes = attributes;
}


@Override
public void visit(String attributeName, Object attributeValue) {
this.attributes.put(attributeName, attributeValue);
}

@Override
public AnnotationVisitor visitAnnotation(String attributeName, String asmTypeDescriptor) {
String annotationType = Type.getType(asmTypeDescriptor).getClassName();
AnnotationAttributes nestedAttributes = new AnnotationAttributes(annotationType, this.classLoader);
this.attributes.put(attributeName, nestedAttributes);
return new RecursiveAnnotationAttributesVisitor(annotationType, nestedAttributes, this.classLoader);
}

@Override
public AnnotationVisitor visitArray(String attributeName) {
return new RecursiveAnnotationArrayVisitor(attributeName, this.attributes, this.classLoader);
}

@Override
public void visitEnum(String attributeName, String asmTypeDescriptor, String attributeValue) {
Object newValue = getEnumValue(asmTypeDescriptor, attributeValue);
visit(attributeName, newValue);
}

protected Object getEnumValue(String asmTypeDescriptor, String attributeValue) {
Object valueToUse = attributeValue;
try {
Class<?> enumType = ClassUtils.forName(Type.getType(asmTypeDescriptor).getClassName(), this.classLoader);
Field enumConstant = ReflectionUtils.findField(enumType, attributeValue);
if (enumConstant != null) {
ReflectionUtils.makeAccessible(enumConstant);
valueToUse = enumConstant.get(null);
}
}
catch (ClassNotFoundException | NoClassDefFoundError ex) {
logger.debug("Failed to classload enum type while reading annotation metadata", ex);
}
catch (IllegalAccessException | AccessControlException ex) {
logger.debug("Could not access enum value while reading annotation metadata", ex);
}
return valueToUse;
}

}
Loading
Loading