1
0
mirror of https://gitee.com/dcren/initializr.git synced 2025-04-05 17:38:06 +08:00

Handle metadata resolution failures properly

See gh-1039
This commit is contained in:
bono007 2019-11-16 19:32:48 -06:00 committed by Stephane Nicoll
parent 4be0e94954
commit 81c66cd19e
7 changed files with 106 additions and 5 deletions
initializr-metadata/src
main/java/io/spring/initializr/metadata
test/java/io/spring/initializr/metadata
initializr-web/src

View File

@ -19,6 +19,7 @@ package io.spring.initializr.metadata;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
@ -185,10 +186,25 @@ public class BillOfMaterials {
* additional BOMs to use, if any.
* @param bootVersion the Spring Boot version
* @return the bill of materials
* @throws IllegalStateException if bom has mappings, none of which match the
* requested version
*/
public BillOfMaterials resolve(Version bootVersion) {
return this.resolveSafe(bootVersion).orElseThrow(() -> new IllegalStateException(
"No suitable mapping was found for " + this + " and version " + bootVersion));
}
/**
* Resolve this instance according to the specified Spring Boot {@link Version}.
* Return a {@link BillOfMaterials} instance that holds the version, repositories and
* additional BOMs to use, if any.
* @param bootVersion the Spring Boot version
* @return the bill of materials or empty if bom has mappings, none of which match the
* requested version
*/
public Optional<BillOfMaterials> resolveSafe(Version bootVersion) {
if (this.mappings.isEmpty()) {
return this;
return Optional.of(this);
}
for (Mapping mapping : this.mappings) {
@ -202,10 +218,10 @@ public class BillOfMaterials {
.addAll(!mapping.repositories.isEmpty() ? mapping.repositories : this.repositories);
resolvedBom.additionalBoms
.addAll(!mapping.additionalBoms.isEmpty() ? mapping.additionalBoms : this.additionalBoms);
return resolvedBom;
return Optional.of(resolvedBom);
}
}
throw new IllegalStateException("No suitable mapping was found for " + this + " and version " + bootVersion);
return Optional.empty();
}
@Override

View File

@ -123,6 +123,15 @@ class BillOfMaterialsTests {
.withMessageContaining("1.4.1.RELEASE");
}
@Test
void noRangeAvailableSafe() {
BillOfMaterials bom = BillOfMaterials.create("com.example", "bom");
bom.getMappings().add(Mapping.create("[1.2.0.RELEASE,1.3.0.M1)", "1.1.0"));
bom.getMappings().add(Mapping.create("[1.3.0.M1, 1.4.0.M1)", "1.2.0"));
bom.validate();
assertThat(bom.resolveSafe(Version.parse("1.4.1.RELEASE"))).isEmpty();
}
@Test
void resolveRangeWithVariablePatch() {
BillOfMaterials bom = BillOfMaterials.create("com.example", "bom", "1.0.0");

View File

@ -0,0 +1,31 @@
/*
* Copyright 2012-2019 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 io.spring.initializr.web.controller;
/**
* Thrown when a metadata request is invalid.
*
* @author Chris Bono
*/
@SuppressWarnings("serial")
public class InvalidMetadataRequestException extends RuntimeException {
public InvalidMetadataRequestException(String message) {
super(message);
}
}

View File

@ -16,8 +16,11 @@
package io.spring.initializr.web.controller;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import javax.servlet.http.HttpServletResponse;
import io.spring.initializr.generator.version.Version;
import io.spring.initializr.metadata.DependencyMetadata;
import io.spring.initializr.metadata.DependencyMetadataProvider;
@ -30,9 +33,11 @@ import io.spring.initializr.web.mapper.InitializrMetadataV2JsonMapper;
import io.spring.initializr.web.mapper.InitializrMetadataVersion;
import org.springframework.http.CacheControl;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
@ -85,6 +90,12 @@ public class ProjectMetadataController extends AbstractMetadataController {
return dependenciesFor(InitializrMetadataVersion.V2_1, bootVersion);
}
@ExceptionHandler
public void invalidMetadaRequest(HttpServletResponse response, InvalidMetadataRequestException ex)
throws IOException {
response.sendError(HttpStatus.BAD_REQUEST.value(), ex.getMessage());
}
/**
* Return the {@link CacheControl} response headers to use for the specified
* {@link InitializrMetadata metadata}. If no cache should be applied

View File

@ -26,6 +26,7 @@ import io.spring.initializr.metadata.DependencyMetadata;
import io.spring.initializr.metadata.DependencyMetadataProvider;
import io.spring.initializr.metadata.InitializrMetadata;
import io.spring.initializr.metadata.Repository;
import io.spring.initializr.web.controller.InvalidMetadataRequestException;
import org.springframework.cache.annotation.Cacheable;
@ -57,8 +58,12 @@ public class DefaultDependencyMetadataProvider implements DependencyMetadataProv
Map<String, BillOfMaterials> boms = new LinkedHashMap<>();
for (Dependency dependency : dependencies.values()) {
if (dependency.getBom() != null) {
boms.put(dependency.getBom(),
metadata.getConfiguration().getEnv().getBoms().get(dependency.getBom()).resolve(bootVersion));
BillOfMaterials bom = metadata.getConfiguration().getEnv().getBoms().get(dependency.getBom())
.resolveSafe(bootVersion)
.orElseThrow(() -> new InvalidMetadataRequestException(String.format(
"Dependency '%s' points to Bom '%s' that is not compatible with requested platform version '%s'.",
dependency.getId(), dependency.getBom(), bootVersion)));
boms.put(dependency.getBom(), bom);
}
}
// Each resolved bom may require additional repositories

View File

@ -60,6 +60,18 @@ public class ProjectMetadataControllerIntegrationTests extends AbstractInitializ
validateMetadata(response, InitializrMetadataVersion.V2.getMediaType(), "2.0.0", JSONCompareMode.STRICT);
}
@Test
void metadataWithInvalidBootVersion() {
try {
execute("/dependencies?bootVersion=1.5.17.RELEASE", String.class, "application/vnd.initializr.v2.1+json",
"application/json");
}
catch (HttpClientErrorException ex) {
assertThat(ex.getStatusCode()).isEqualTo(HttpStatus.BAD_REQUEST);
assertThat(ex.getResponseBodyAsString().contains("1.5.17.RELEASE"));
}
}
@Test
void metadataWithCurrentAcceptHeader() {
getRequests().setFields("_links.maven-project", "dependencies.values[0]", "type.values[0]",

View File

@ -23,9 +23,11 @@ import io.spring.initializr.metadata.Dependency;
import io.spring.initializr.metadata.DependencyMetadata;
import io.spring.initializr.metadata.DependencyMetadataProvider;
import io.spring.initializr.metadata.InitializrMetadata;
import io.spring.initializr.web.controller.InvalidMetadataRequestException;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
/**
* @author Stephane Nicoll
@ -74,6 +76,21 @@ class DefaultDependencyMetadataProviderTests {
assertThat(anotherDependencyMetadata.getDependencies().get("first").getVersion()).isEqualTo("0.2.0.RELEASE");
}
@Test
void resolveBomInvalidBootVersion() {
Dependency first = Dependency.withId("first", "org.foo", "first");
first.setRepository("repo-foo");
first.setBom("bom-foo");
BillOfMaterials bom = BillOfMaterials.create("org.foo", "bom");
bom.getMappings()
.add(BillOfMaterials.Mapping.create("[1.0.0.RELEASE, 1.1.0.RELEASE)", "2.0.0.RELEASE", "repo-foo"));
InitializrMetadata metadata = InitializrMetadataTestBuilder.withDefaults().addBom("bom-foo", bom)
.addRepository("repo-foo", "foo", "http://localhost", false).addDependencyGroup("test", first).build();
assertThatExceptionOfType(InvalidMetadataRequestException.class)
.isThrownBy(() -> this.provider.get(metadata, Version.parse("1.1.5.RELEASE")))
.withMessageContainingAll(first.getId(), first.getBom(), "1.1.5.RELEASE");
}
@Test
void addRepoAndRemoveDuplicates() {
Dependency first = Dependency.withId("first", "org.foo", "first");