Support loading of base64 encoded values as Resources

An ApplicationResourceLoader has been introduced to support loading
resources using registered ProtocolResolvers. All usages of
DefaultResourceLoader and ResourceUtils have been changed to use
the ApplicationResourceLoader.

A Base64ProtocolResolver has been added to support resources of type
`base64:` that contain base64 encoded values.

Closes gh-36033
This commit is contained in:
Scott Frederick
2024-03-20 10:33:35 -05:00
committed by Scott Frederick
parent 558d811b0a
commit 0962025c4b
20 changed files with 458 additions and 69 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2022-2023 the original author or authors.
* Copyright 2022-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.
@@ -26,12 +26,16 @@ import java.util.List;
import java.util.stream.Collectors;
import com.tngtech.archunit.base.DescribedPredicate;
import com.tngtech.archunit.core.domain.JavaCall;
import com.tngtech.archunit.core.domain.JavaClass;
import com.tngtech.archunit.core.domain.JavaClass.Predicates;
import com.tngtech.archunit.core.domain.JavaClasses;
import com.tngtech.archunit.core.domain.JavaMethod;
import com.tngtech.archunit.core.domain.JavaParameter;
import com.tngtech.archunit.core.domain.properties.CanBeAnnotated;
import com.tngtech.archunit.core.domain.properties.HasName;
import com.tngtech.archunit.core.domain.properties.HasOwner.Predicates.With;
import com.tngtech.archunit.core.domain.properties.HasParameterTypes;
import com.tngtech.archunit.core.importer.ClassFileImporter;
import com.tngtech.archunit.lang.ArchCondition;
import com.tngtech.archunit.lang.ArchRule;
@@ -58,11 +62,14 @@ import org.gradle.api.tasks.PathSensitivity;
import org.gradle.api.tasks.SkipWhenEmpty;
import org.gradle.api.tasks.TaskAction;
import org.springframework.util.ResourceUtils;
/**
* {@link Task} that checks for architecture problems.
*
* @author Andy Wilkinson
* @author Yanming Zhou
* @author Scott Frederick
*/
public abstract class ArchitectureCheck extends DefaultTask {
@@ -75,7 +82,8 @@ public abstract class ArchitectureCheck extends DefaultTask {
allBeanFactoryPostProcessorBeanMethodsShouldBeStaticAndHaveNoParameters(),
noClassesShouldCallStepVerifierStepVerifyComplete(),
noClassesShouldConfigureDefaultStepVerifierTimeout(), noClassesShouldCallCollectorsToList(),
noClassesShouldCallURLEncoderWithStringEncoding(), noClassesShouldCallURLDecoderWithStringEncoding());
noClassesShouldCallURLEncoderWithStringEncoding(), noClassesShouldCallURLDecoderWithStringEncoding(),
noClassesShouldLoadResourcesUsingResourceUtils());
getRuleDescriptions().set(getRules().map((rules) -> rules.stream().map(ArchRule::getDescription).toList()));
}
@@ -208,6 +216,18 @@ public abstract class ArchitectureCheck extends DefaultTask {
.because("java.net.URLDecoder.decode(String s, Charset charset) should be used instead");
}
private ArchRule noClassesShouldLoadResourcesUsingResourceUtils() {
return ArchRuleDefinition.noClasses()
.should()
.callMethodWhere(JavaCall.Predicates.target(With.owner(Predicates.type(ResourceUtils.class)))
.and(JavaCall.Predicates.target(HasName.Predicates.name("getURL")))
.and(JavaCall.Predicates.target(HasParameterTypes.Predicates.rawParameterTypes(String.class)))
.or(JavaCall.Predicates.target(With.owner(Predicates.type(ResourceUtils.class)))
.and(JavaCall.Predicates.target(HasName.Predicates.name("getFile")))
.and(JavaCall.Predicates.target(HasParameterTypes.Predicates.rawParameterTypes(String.class)))))
.because("org.springframework.boot.io.ApplicationResourceLoader should be used instead");
}
public void setClasses(FileCollection classes) {
this.classes = classes;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2023 the original author or authors.
* Copyright 2012-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.
@@ -36,6 +36,7 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
* Tests for {@link ArchitectureCheck}.
*
* @author Andy Wilkinson
* @author Scott Frederick
*/
class ArchitectureCheckTests {
@@ -121,6 +122,22 @@ class ArchitectureCheckTests {
});
}
@Test
void whenClassLoadsResourceUsingResourceUtilsTaskFailsAndWritesReport() throws Exception {
prepareTask("resources/loads", (architectureCheck) -> {
assertThatExceptionOfType(GradleException.class).isThrownBy(architectureCheck::checkArchitecture);
assertThat(failureReport(architectureCheck)).isNotEmpty();
});
}
@Test
void whenClassUsesResourceUtilsWithoutLoadingResourcesTaskSucceedsAndWritesAnEmptyReport() throws Exception {
prepareTask("resources/noloads", (architectureCheck) -> {
architectureCheck.checkArchitecture();
assertThat(failureReport(architectureCheck)).isEmpty();
});
}
private void prepareTask(String classes, Callback<ArchitectureCheck> callback) throws Exception {
File projectDir = new File(this.temp, "project");
projectDir.mkdirs();

View File

@@ -0,0 +1,29 @@
/*
* Copyright 2012-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.springframework.boot.build.architecture.resources.loads;
import java.io.FileNotFoundException;
import org.springframework.util.ResourceUtils;
public class ResourceUtilsResourceLoader {
void getResource() throws FileNotFoundException {
ResourceUtils.getURL("gradle.properties");
}
}

View File

@@ -0,0 +1,32 @@
/*
* Copyright 2012-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.springframework.boot.build.architecture.resources.noloads;
import java.net.MalformedURLException;
import java.net.URL;
import org.springframework.util.ResourceUtils;
public class ResourceUtilsWithoutLoading {
void inspectResourceLocation() throws MalformedURLException {
ResourceUtils.isUrl("gradle.properties");
ResourceUtils.isFileURL(new URL("gradle.properties"));
"test".startsWith(ResourceUtils.FILE_URL_PREFIX);
}
}