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

Make SingleSelectCapability thread-safe

Closes gh-1105
This commit is contained in:
Andy Wilkinson 2020-06-18 16:52:06 +01:00
parent 9f19c6fa50
commit 42b701ab1a
4 changed files with 66 additions and 23 deletions
initializr-generator-test/src/main/java/io/spring/initializr/generator/test
initializr-metadata/src
main/java/io/spring/initializr/metadata
test/java/io/spring/initializr/metadata

View File

@ -126,7 +126,7 @@ public class InitializrMetadataTestBuilder {
packaging.setId(id);
packaging.setName(id);
packaging.setDefault(defaultValue);
it.getPackagings().getContent().add(packaging);
it.getPackagings().addContent(packaging);
});
return this;
}
@ -141,7 +141,7 @@ public class InitializrMetadataTestBuilder {
element.setId(version);
element.setName(version);
element.setDefault(defaultValue);
it.getJavaVersions().getContent().add(element);
it.getJavaVersions().addContent(element);
});
return this;
}
@ -156,7 +156,7 @@ public class InitializrMetadataTestBuilder {
element.setId(id);
element.setName(id);
element.setDefault(defaultValue);
it.getLanguages().getContent().add(element);
it.getLanguages().addContent(element);
});
return this;
}
@ -172,7 +172,7 @@ public class InitializrMetadataTestBuilder {
element.setId(id);
element.setName(id);
element.setDefault(defaultValue);
it.getBootVersions().getContent().add(element);
it.getBootVersions().addContent(element);
});
return this;
}

View File

@ -200,8 +200,7 @@ public class InitializrMetadata {
* @param versionsMetadata the Spring Boot boot versions metadata to use
*/
public void updateSpringBootVersions(List<DefaultMetadataElement> versionsMetadata) {
this.bootVersions.getContent().clear();
this.bootVersions.getContent().addAll(versionsMetadata);
this.bootVersions.setContent(versionsMetadata);
List<Version> bootVersions = this.bootVersions.getContent().stream().map((it) -> Version.parse(it.getId()))
.collect(Collectors.toList());
VersionParser parser = new VersionParser(bootVersions);

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2019 the original author or authors.
* Copyright 2012-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,8 +16,13 @@
package io.spring.initializr.metadata;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.function.Consumer;
import java.util.function.Function;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
@ -30,7 +35,9 @@ import com.fasterxml.jackson.annotation.JsonProperty;
public class SingleSelectCapability extends ServiceCapability<List<DefaultMetadataElement>>
implements Defaultable<DefaultMetadataElement> {
private final List<DefaultMetadataElement> content = new CopyOnWriteArrayList<>();
private final List<DefaultMetadataElement> content = new ArrayList<>();
private final ReadWriteLock contentLock = new ReentrantReadWriteLock();
@JsonCreator
SingleSelectCapability(@JsonProperty("id") String id) {
@ -43,7 +50,18 @@ public class SingleSelectCapability extends ServiceCapability<List<DefaultMetada
@Override
public List<DefaultMetadataElement> getContent() {
return this.content;
return Collections.unmodifiableList(withReadableContent(ArrayList::new));
}
public void addContent(DefaultMetadataElement element) {
withWritableContent((content) -> content.add(element));
}
public void setContent(List<DefaultMetadataElement> newContent) {
withWritableContent((content) -> {
content.clear();
content.addAll(newContent);
});
}
/**
@ -51,7 +69,8 @@ public class SingleSelectCapability extends ServiceCapability<List<DefaultMetada
*/
@Override
public DefaultMetadataElement getDefault() {
return this.content.stream().filter(DefaultMetadataElement::isDefault).findFirst().orElse(null);
return withReadableContent(
(content) -> content.stream().filter(DefaultMetadataElement::isDefault).findFirst().orElse(null));
}
/**
@ -60,16 +79,39 @@ public class SingleSelectCapability extends ServiceCapability<List<DefaultMetada
* @return the element or {@code null}
*/
public DefaultMetadataElement get(String id) {
return this.content.stream().filter((it) -> id.equals(it.getId())).findFirst().orElse(null);
return withReadableContent(
(content) -> content.stream().filter((it) -> id.equals(it.getId())).findFirst().orElse(null));
}
@Override
public void merge(List<DefaultMetadataElement> otherContent) {
otherContent.forEach((it) -> {
if (get(it.getId()) == null) {
this.content.add(it);
}
withWritableContent((content) -> {
otherContent.forEach((it) -> {
if (get(it.getId()) == null) {
this.content.add(it);
}
});
});
}
private <T> T withReadableContent(Function<List<DefaultMetadataElement>, T> consumer) {
this.contentLock.readLock().lock();
try {
return consumer.apply(this.content);
}
finally {
this.contentLock.readLock().unlock();
}
}
private void withWritableContent(Consumer<List<DefaultMetadataElement>> consumer) {
this.contentLock.writeLock().lock();
try {
consumer.accept(this.content);
}
finally {
this.contentLock.writeLock().unlock();
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2019 the original author or authors.
* Copyright 2012-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,8 @@
package io.spring.initializr.metadata;
import java.util.Arrays;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
@ -34,17 +36,17 @@ class SingleSelectCapabilityTests {
@Test
void defaultNoDefault() {
SingleSelectCapability capability = new SingleSelectCapability("test");
capability.getContent().add(DefaultMetadataElement.create("foo", false));
capability.getContent().add(DefaultMetadataElement.create("bar", false));
capability.setContent(Arrays.asList(DefaultMetadataElement.create("foo", false),
DefaultMetadataElement.create("bar", false)));
assertThat(capability.getDefault()).isNull();
}
@Test
void defaultType() {
SingleSelectCapability capability = new SingleSelectCapability("test");
capability.getContent().add(DefaultMetadataElement.create("foo", false));
DefaultMetadataElement first = DefaultMetadataElement.create("foo", false);
DefaultMetadataElement second = DefaultMetadataElement.create("bar", true);
capability.getContent().add(second);
capability.setContent(Arrays.asList(first, second));
assertThat(capability.getDefault()).isEqualTo(second);
}
@ -52,11 +54,11 @@ class SingleSelectCapabilityTests {
void mergeAddEntry() {
SingleSelectCapability capability = new SingleSelectCapability("test");
DefaultMetadataElement foo = DefaultMetadataElement.create("foo", false);
capability.getContent().add(foo);
capability.setContent(Arrays.asList(foo));
SingleSelectCapability anotherCapability = new SingleSelectCapability("test");
DefaultMetadataElement bar = DefaultMetadataElement.create("bar", false);
anotherCapability.getContent().add(bar);
anotherCapability.setContent(Arrays.asList(bar));
capability.merge(anotherCapability);
assertThat(capability.getContent()).hasSize(2);