Skip to content

Commit

Permalink
Allow customization of fields and template variables
Browse files Browse the repository at this point in the history
Closes gh-1626
  • Loading branch information
mhalbritter committed Feb 10, 2025
1 parent 274d842 commit 6db9d41
Show file tree
Hide file tree
Showing 5 changed files with 124 additions and 42 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -39,24 +39,33 @@ public class DependencyMetadataV21JsonMapper implements DependencyMetadataJsonMa

@Override
public String write(DependencyMetadata metadata) {
ObjectNode json = nodeFactory.objectNode();
json.put("bootVersion", metadata.getBootVersion().toString());
json.set("dependencies",
ObjectNode parent = nodeFactory.objectNode();
parent.put("bootVersion", metadata.getBootVersion().toString());
parent.set("dependencies",
mapNode(metadata.getDependencies()
.entrySet()
.stream()
.collect(Collectors.toMap(Map.Entry::getKey, (entry) -> mapDependency(entry.getValue())))));
json.set("repositories",
parent.set("repositories",
mapNode(metadata.getRepositories()
.entrySet()
.stream()
.collect(Collectors.toMap(Map.Entry::getKey, (entry) -> mapRepository(entry.getValue())))));
json.set("boms",
parent.set("boms",
mapNode(metadata.getBoms()
.entrySet()
.stream()
.collect(Collectors.toMap(Map.Entry::getKey, (entry) -> mapBom(entry.getValue())))));
return json.toString();
customizeParent(parent, metadata);
return parent.toString();
}

/**
* Customizes the parent.
* @param parent the parent
* @param metadata the metadata
*/
protected void customizeParent(ObjectNode parent, DependencyMetadata metadata) {
}

private static JsonNode mapDependency(Dependency dep) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

package io.spring.initializr.web.mapper;

import java.util.Collection;
import java.util.Collections;
import java.util.List;

import com.fasterxml.jackson.databind.node.ObjectNode;
Expand All @@ -41,7 +43,19 @@ public class InitializrMetadataV21JsonMapper extends InitializrMetadataV2JsonMap

private final TemplateVariables dependenciesVariables;

/**
* Create a new instance.
*/
public InitializrMetadataV21JsonMapper() {
this(Collections.emptyList());
}

/**
* Create a new instance using the additional template variables.
* @param additionalTemplateVariables the additional template variables
*/
public InitializrMetadataV21JsonMapper(Collection<? extends TemplateVariable> additionalTemplateVariables) {
super(additionalTemplateVariables);
this.dependenciesVariables = new TemplateVariables(
new TemplateVariable("bootVersion", TemplateVariable.VariableType.REQUEST_PARAM));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,14 @@

package io.spring.initializr.web.mapper;

import java.util.Collection;
import java.util.Collections;

import io.spring.initializr.generator.version.Version;
import io.spring.initializr.generator.version.VersionRange;

import org.springframework.hateoas.TemplateVariable;

/**
* A {@link InitializrMetadataJsonMapper} handling the metadata format for v2.2
* <p>
Expand All @@ -29,6 +34,21 @@
*/
public class InitializrMetadataV22JsonMapper extends InitializrMetadataV21JsonMapper {

/**
* Create a new instance.
*/
public InitializrMetadataV22JsonMapper() {
this(Collections.emptyList());
}

/**
* Create a new instance using the additional template variables.
* @param additionalTemplateVariables the additional template variables
*/
public InitializrMetadataV22JsonMapper(Collection<? extends TemplateVariable> additionalTemplateVariables) {
super(additionalTemplateVariables);
}

@Override
protected String formatVersion(String versionId) {
return versionId;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@

package io.spring.initializr.web.mapper;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
Expand Down Expand Up @@ -49,26 +52,40 @@
*
* @author Stephane Nicoll
* @author Guillaume Gerbaud
* @author Moritz Halbritter
*/
public class InitializrMetadataV2JsonMapper implements InitializrMetadataJsonMapper {

private static final JsonNodeFactory nodeFactory = JsonNodeFactory.instance;

private final TemplateVariables templateVariables;

/**
* Create a new instance.
*/
public InitializrMetadataV2JsonMapper() {
this.templateVariables = new TemplateVariables(
new TemplateVariable("dependencies", TemplateVariable.VariableType.REQUEST_PARAM),
new TemplateVariable("packaging", TemplateVariable.VariableType.REQUEST_PARAM),
new TemplateVariable("javaVersion", TemplateVariable.VariableType.REQUEST_PARAM),
new TemplateVariable("language", TemplateVariable.VariableType.REQUEST_PARAM),
new TemplateVariable("bootVersion", TemplateVariable.VariableType.REQUEST_PARAM),
new TemplateVariable("groupId", TemplateVariable.VariableType.REQUEST_PARAM),
new TemplateVariable("artifactId", TemplateVariable.VariableType.REQUEST_PARAM),
new TemplateVariable("version", TemplateVariable.VariableType.REQUEST_PARAM),
new TemplateVariable("name", TemplateVariable.VariableType.REQUEST_PARAM),
new TemplateVariable("description", TemplateVariable.VariableType.REQUEST_PARAM),
new TemplateVariable("packageName", TemplateVariable.VariableType.REQUEST_PARAM));
this(Collections.emptyList());
}

/**
* Create a new instance using the additional template variables.
* @param additionalTemplateVariables the additional template variables
*/
public InitializrMetadataV2JsonMapper(Collection<? extends TemplateVariable> additionalTemplateVariables) {
List<TemplateVariable> templateVariables = new ArrayList<>();
templateVariables.add(new TemplateVariable("dependencies", TemplateVariable.VariableType.REQUEST_PARAM));
templateVariables.add(new TemplateVariable("packaging", TemplateVariable.VariableType.REQUEST_PARAM));
templateVariables.add(new TemplateVariable("javaVersion", TemplateVariable.VariableType.REQUEST_PARAM));
templateVariables.add(new TemplateVariable("language", TemplateVariable.VariableType.REQUEST_PARAM));
templateVariables.add(new TemplateVariable("bootVersion", TemplateVariable.VariableType.REQUEST_PARAM));
templateVariables.add(new TemplateVariable("groupId", TemplateVariable.VariableType.REQUEST_PARAM));
templateVariables.add(new TemplateVariable("artifactId", TemplateVariable.VariableType.REQUEST_PARAM));
templateVariables.add(new TemplateVariable("version", TemplateVariable.VariableType.REQUEST_PARAM));
templateVariables.add(new TemplateVariable("name", TemplateVariable.VariableType.REQUEST_PARAM));
templateVariables.add(new TemplateVariable("description", TemplateVariable.VariableType.REQUEST_PARAM));
templateVariables.add(new TemplateVariable("packageName", TemplateVariable.VariableType.REQUEST_PARAM));
templateVariables.addAll(additionalTemplateVariables);
this.templateVariables = new TemplateVariables(templateVariables);
}

protected JsonNodeFactory nodeFactory() {
Expand All @@ -77,21 +94,30 @@ protected JsonNodeFactory nodeFactory() {

@Override
public String write(InitializrMetadata metadata, String appUrl) {
ObjectNode delegate = nodeFactory.objectNode();
links(delegate, metadata.getTypes().getContent(), appUrl);
dependencies(delegate, metadata.getDependencies());
type(delegate, metadata.getTypes());
singleSelect(delegate, metadata.getPackagings());
singleSelect(delegate, metadata.getJavaVersions());
singleSelect(delegate, metadata.getLanguages());
singleSelect(delegate, metadata.getBootVersions(), this::mapVersionMetadata, this::formatVersion);
text(delegate, metadata.getGroupId());
text(delegate, metadata.getArtifactId());
text(delegate, metadata.getVersion());
text(delegate, metadata.getName());
text(delegate, metadata.getDescription());
text(delegate, metadata.getPackageName());
return delegate.toString();
ObjectNode parent = nodeFactory.objectNode();
links(parent, metadata.getTypes().getContent(), appUrl);
dependencies(parent, metadata.getDependencies());
type(parent, metadata.getTypes());
singleSelect(parent, metadata.getPackagings());
singleSelect(parent, metadata.getJavaVersions());
singleSelect(parent, metadata.getLanguages());
singleSelect(parent, metadata.getBootVersions(), this::mapVersionMetadata, this::formatVersion);
text(parent, metadata.getGroupId());
text(parent, metadata.getArtifactId());
text(parent, metadata.getVersion());
text(parent, metadata.getName());
text(parent, metadata.getDescription());
text(parent, metadata.getPackageName());
customizeParent(parent, metadata);
return parent.toString();
}

/**
* Customizes the parent.
* @param parent the parent
* @param metadata the metadata
*/
protected void customizeParent(ObjectNode parent, InitializrMetadata metadata) {
}

protected ObjectNode links(ObjectNode parent, List<Type> types, String appUrl) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

package io.spring.initializr.web.mapper;

import java.util.List;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
Expand All @@ -25,6 +27,8 @@
import io.spring.initializr.metadata.InitializrMetadata;
import org.junit.jupiter.api.Test;

import org.springframework.hateoas.TemplateVariable;

import static org.assertj.core.api.Assertions.assertThat;

/**
Expand Down Expand Up @@ -73,18 +77,27 @@ void platformVersionUsingSemVerUIsNotChanged() throws JsonProcessingException {
assertVersionMetadata(versions.get(2), "2.4.2", "2.4.2");
}

@Test
void shouldAllowCustomization() throws JsonProcessingException {
InitializrMetadataJsonMapper mapper = new InitializrMetadataV22JsonMapper(
List.of(TemplateVariable.requestParameter("testParameter"))) {
@Override
protected void customizeParent(ObjectNode parent, InitializrMetadata metadata) {
parent.put("testField", "testValue");
}
};
String json = mapper.write(
new InitializrMetadataTestBuilder().addType("id", true, "action", "build", "dialect", "format").build(),
"http://localhost");
JsonNode result = objectMapper.readTree(json);
assertThat(result.get("testField").asText()).isEqualTo("testValue");
assertThat(result.get("_links").get("id").get("href").asText()).isEqualTo(
"http://localhost/action?type=id{&dependencies,packaging,javaVersion,language,bootVersion,groupId,artifactId,version,name,description,packageName,testParameter}");
}

private void assertVersionMetadata(JsonNode node, String id, String name) {
assertThat(node.get("id").textValue()).isEqualTo(id);
assertThat(node.get("name").textValue()).isEqualTo(name);
}

private Object get(JsonNode result, String path) {
String[] nodes = path.split("\\.");
for (int i = 0; i < nodes.length - 1; i++) {
String node = nodes[i];
result = result.path(node);
}
return result.get(nodes[nodes.length - 1]).textValue();
}

}

3 comments on commit 6db9d41

@luccnunes
Copy link
Contributor

@luccnunes luccnunes commented on 6db9d41 Feb 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Override
public String write(DependencyMetadata metadata) {
    ObjectNode parent = nodeFactory.objectNode();
    parent.put("bootVersion", metadata.getBootVersion().toString());
    parent.set("dependencies", mapDependencies(metadata.getDependencies()));
    parent.set("repositories", mapRepositories(metadata.getRepositories()));
    parent.set("boms", mapBoms(metadata.getBoms()));
    customizeParent(parent, metadata);
    return parent.toString();
}

private ObjectNode mapDependencies(Map<String, Dependency> dependencies) {
    return mapNode(dependencies.entrySet().stream()
            .collect(Collectors.toMap(Map.Entry::getKey, entry -> mapDependency(entry.getValue()))));
}

private ObjectNode mapRepositories(Map<String, Repository> repositories) {
    return mapNode(repositories.entrySet().stream()
            .collect(Collectors.toMap(Map.Entry::getKey, entry -> mapRepository(entry.getValue()))));
}

private ObjectNode mapBoms(Map<String, Bom> boms) {
    return mapNode(boms.entrySet().stream()
            .collect(Collectors.toMap(Map.Entry::getKey, entry -> mapBom(entry.getValue()))));
}

Wouldn't it be more readable to separate the maps by method?

@mhalbritter
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd be okay with that change. Do you want to open a PR?

@luccnunes
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes I will open the pr

Please sign in to comment.