You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by da...@apache.org on 2021/06/18 15:04:52 UTC
[isis] 01/01: ISIS-2751: fixes ModuleWithFixturesService
This is an automated email from the ASF dual-hosted git repository.
danhaywood pushed a commit to branch ISIS-2751
in repository https://gitbox.apache.org/repos/asf/isis.git
commit ad27a281a603e9d5b0913a9c5b86ab6feddb7ebc
Author: danhaywood <da...@haywood-associates.co.uk>
AuthorDate: Fri Jun 18 15:44:56 2021 +0100
ISIS-2751: fixes ModuleWithFixturesService
to return sequenced
---
.../SpringServiceInjectOrderTest.java | 212 +++++++++++++--------
.../applib/modules/ModuleWithFixturesService.java | 90 ++++++---
2 files changed, 195 insertions(+), 107 deletions(-)
diff --git a/regressiontests/stable-bootstrapping/src/test/java/org/apache/isis/testdomain/bootstrapping/SpringServiceInjectOrderTest.java b/regressiontests/stable-bootstrapping/src/test/java/org/apache/isis/testdomain/bootstrapping/SpringServiceInjectOrderTest.java
index 436acf6..3527d32 100644
--- a/regressiontests/stable-bootstrapping/src/test/java/org/apache/isis/testdomain/bootstrapping/SpringServiceInjectOrderTest.java
+++ b/regressiontests/stable-bootstrapping/src/test/java/org/apache/isis/testdomain/bootstrapping/SpringServiceInjectOrderTest.java
@@ -53,11 +53,14 @@ import org.apache.isis.testdomain.conf.Configuration_headless;
import lombok.Getter;
import lombok.val;
+=======
+ >>>>>>>4dd5fb2460(ISIS-2751:fixes ModuleWithFixturesService)
+
@SpringBootTest(
- classes = {
+ classes = {
Configuration_headless.class,
SpringServiceInjectOrderTest.TestConfig.class,
-
+
SpringServiceInjectOrderTest.Average.class,
SpringServiceInjectOrderTest.Excellent.class,
SpringServiceInjectOrderTest.Good.class,
@@ -68,89 +71,19 @@ import lombok.val;
// "logging.level.ObjectSpecificationAbstract=TRACE"
})
@TestPropertySource({
- IsisPresets.SilenceMetaModel,
- IsisPresets.SilenceProgrammingModel,
- IsisPresets.UseLog4j2Test
+ IsisPresets.SilenceMetaModel,
+ IsisPresets.SilenceProgrammingModel,
+ IsisPresets.UseLog4j2Test
})
class SpringServiceInjectOrderTest {
- @Configuration
- static class TestConfig {
- }
-
- interface Rating {
- int getRating();
- }
-
- @Service
- @Order(PriorityPrecedence.EARLY)
- @Qualifier("tallest")
- @Named("withExcellentName")
- static class Excellent implements Rating {
-
- @Override
- public int getRating() {
- return 1;
- }
- }
-
- @Service
- @Priority(PriorityPrecedence.MIDPOINT)
- @Qualifier("tall")
- @Named("withGoodName")
- static class Good implements Rating {
+ @Inject
+ DummyService dummyService;
+ @Inject
+ ServiceInjector serviceInjector;
+ @Inject
+ OrderComparator orderComparator;
- @Override
- public int getRating() {
- return 2;
- }
- }
-
- @Service
- @Order(PriorityPrecedence.LAST)
- @Qualifier("middle")
- @Named("withAverageName")
- static class Average implements Rating {
-
- @Override
- public int getRating() {
- return 3;
- }
- }
-
- @Service
- static class DummyService {
- @Inject @Getter MessageService messageService;
- @Inject @Getter List<Rating> ratings;
- @Inject @Getter Rating primaryRating;
- @Inject @Getter Rating someArbitraryRating;
- @Inject @Getter @Qualifier("tallest") Rating qualifiedRating1;
- @Inject @Getter @Qualifier("tall") Rating qualifiedRating2;
- @Inject @Getter @Qualifier("middle") Rating qualifiedRating3;
- @Inject @Getter Rating tallest;
- @Inject @Getter Rating mostExcellentName;
-
- // this doesn't bootstrap, because matching is done using the service's @Qualifier, not the service's @Name
- // @Inject @Getter @Qualifier("mostExcellentName") Rating namedRating1;
- }
-
- @DomainObject
- static class DummyObject {
- @Inject @Getter MessageService messageService;
- @Inject @Getter List<Rating> ratings;
- @Inject @Getter Rating someArbitraryRating;
- @Inject @Getter @Qualifier("tallest") Rating qualifiedRating1;
- @Inject @Getter @Qualifier("tall") Rating qualifiedRating2;
- @Inject @Getter @Qualifier("middle") Rating qualifiedRating3;
- @Inject @Getter Rating tallest;
- @Inject @Getter Rating mostExcellentName;
- }
-
-
- @Inject DummyService dummyService;
- @Inject ServiceInjector serviceInjector;
- @Inject OrderComparator orderComparator;
-
@BeforeEach
void beforeEach() {
@@ -160,7 +93,7 @@ class SpringServiceInjectOrderTest {
void defaultOrdering_shouldConsiderAnnotations() throws IOException {
assertTrue(orderComparator instanceof AnnotationAwareOrderComparator);
}
-
+
@Test
void injectionOnServices_shouldFollowOrder() throws IOException {
@@ -188,7 +121,7 @@ class SpringServiceInjectOrderTest {
// does NOT match field name to @Qualifier
assertThat(dummyService.getMostExcellentName().getRating(), is(equalTo(2))); // rather than '1'... so defaulted to @Primary
}
-
+
@Test
void injectionOnObjects_shouldFollowOrder() throws IOException {
@@ -221,4 +154,117 @@ class SpringServiceInjectOrderTest {
}
+
+ interface Rating {
+ int getRating();
+ }
+
+ @Configuration
+ static class TestConfig {
+ }
+
+ @Service
+ @Order(PriorityPrecedence.EARLY)
+ @Qualifier("tallest")
+ @Named("withExcellentName")
+ static class Excellent implements Rating {
+
+ @Override
+ public int getRating() {
+ return 1;
+ }
+ }
+
+ @Service
+ @Priority(PriorityPrecedence.MIDPOINT)
+ @Qualifier("tall")
+ @Named("withGoodName")
+ static class Good implements Rating {
+
+ @Override
+ public int getRating() {
+ return 2;
+ }
+ }
+
+ @Service
+ @Order(PriorityPrecedence.LAST)
+ @Qualifier("middle")
+ @Named("withAverageName")
+ static class Average implements Rating {
+
+ @Override
+ public int getRating() {
+ return 3;
+ }
+ }
+
+ @Service
+ static class DummyService {
+ @Inject
+ @Getter
+ MessageService messageService;
+ @Inject
+ @Getter
+ List<Rating> ratings;
+ @Inject
+ @Getter
+ Rating primaryRating;
+ @Inject
+ @Getter
+ Rating someArbitraryRating;
+ @Inject
+ @Getter
+ @Qualifier("tallest")
+ Rating qualifiedRating1;
+ @Inject
+ @Getter
+ @Qualifier("tall")
+ Rating qualifiedRating2;
+ @Inject
+ @Getter
+ @Qualifier("middle")
+ Rating qualifiedRating3;
+ @Inject
+ @Getter
+ Rating tallest;
+ @Inject
+ @Getter
+ Rating mostExcellentName;
+
+ // this doesn't bootstrap, because matching is done using the service's @Qualifier, not the service's @Name
+ // @Inject @Getter @Qualifier("mostExcellentName") Rating namedRating1;
+ }
+
+ @DomainObject
+ static class DummyObject {
+ @Inject
+ @Getter
+ MessageService messageService;
+ @Inject
+ @Getter
+ List<Rating> ratings;
+ @Inject
+ @Getter
+ Rating someArbitraryRating;
+ @Inject
+ @Getter
+ @Qualifier("tallest")
+ Rating qualifiedRating1;
+ @Inject
+ @Getter
+ @Qualifier("tall")
+ Rating qualifiedRating2;
+ @Inject
+ @Getter
+ @Qualifier("middle")
+ Rating qualifiedRating3;
+ @Inject
+ @Getter
+ Rating tallest;
+ @Inject
+ @Getter
+ Rating mostExcellentName;
+ }
+
}
diff --git a/testing/fixtures/applib/src/main/java/org/apache/isis/testing/fixtures/applib/modules/ModuleWithFixturesService.java b/testing/fixtures/applib/src/main/java/org/apache/isis/testing/fixtures/applib/modules/ModuleWithFixturesService.java
index de2b122..364f5f9 100644
--- a/testing/fixtures/applib/src/main/java/org/apache/isis/testing/fixtures/applib/modules/ModuleWithFixturesService.java
+++ b/testing/fixtures/applib/src/main/java/org/apache/isis/testing/fixtures/applib/modules/ModuleWithFixturesService.java
@@ -18,18 +18,15 @@
*/
package org.apache.isis.testing.fixtures.applib.modules;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-
-import javax.annotation.Priority;
-import javax.inject.Inject;
-import javax.inject.Named;
-
+import lombok.Data;
+import lombok.extern.log4j.Log4j2;
+import lombok.val;
+import org.apache.isis.applib.annotation.PriorityPrecedence;
+import org.apache.isis.core.metamodel.facets.Annotations;
+import org.apache.isis.subdomains.spring.applib.service.BeanDescriptor;
+import org.apache.isis.subdomains.spring.applib.service.ContextBeans;
+import org.apache.isis.subdomains.spring.applib.service.SpringBeansService;
+import org.apache.isis.testing.fixtures.applib.fixturescripts.FixtureScript;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Configuration;
@@ -38,16 +35,11 @@ import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;
-import org.apache.isis.applib.annotation.PriorityPrecedence;
-import org.apache.isis.core.metamodel.facets.Annotations;
-import org.apache.isis.subdomains.spring.applib.service.BeanDescriptor;
-import org.apache.isis.subdomains.spring.applib.service.ContextBeans;
-import org.apache.isis.subdomains.spring.applib.service.SpringBeansService;
-import org.apache.isis.testing.fixtures.applib.fixturescripts.FixtureScript;
-
-import lombok.Data;
-import lombok.val;
-import lombok.extern.log4j.Log4j2;
+import javax.annotation.Priority;
+import javax.inject.Inject;
+import javax.inject.Named;
+import java.util.*;
+import java.util.stream.Collectors;
/**
* @since 2.x {@index}
@@ -95,10 +87,14 @@ public class ModuleWithFixturesService {
}
public List<ModuleWithFixturesDescriptor> modules() {
+ val beans = springBeansService.beans();
+ val modules = modulesWithin(beans);
+ return sequenced(modules);
+ }
+ static List<ModuleWithFixturesDescriptor> modulesWithin(Map<String, ContextBeans> beans) {
final List<ModuleWithFixturesDescriptor> descriptors = new ArrayList<>();
- final Map<String, ContextBeans> contexts = springBeansService.beans();
- for (Map.Entry<String, ContextBeans> contextEntry : contexts.entrySet()) {
+ for (Map.Entry<String, ContextBeans> contextEntry : beans.entrySet()) {
final String contextId = contextEntry.getKey();
final ContextBeans contextBeans = contextEntry.getValue();
final ConfigurableApplicationContext context = contextBeans.getContext();
@@ -150,6 +146,52 @@ public class ModuleWithFixturesService {
return descriptors;
}
+
+ static List<ModuleWithFixturesDescriptor> sequenced(List<ModuleWithFixturesDescriptor> modules) {
+ val remaining = new ArrayList<>(modules);
+ val sequenced = new ArrayList<ModuleWithFixturesDescriptor>();
+
+ val moduleByName = new LinkedHashMap<String, ModuleWithFixturesDescriptor>();
+ modules.forEach(module -> {
+ moduleByName.put(module.getBeanName(), module);
+ });
+
+ while(!remaining.isEmpty()) {
+ ModuleWithFixturesDescriptor added = addNextModule(sequenced, remaining, moduleByName);
+ if (added == null) {
+ throw new IllegalStateException(String.format(
+ "Unable to determine next module.\nfound = %s\nremaining = %s",
+ beanNamesOf(sequenced), beanNamesOf(remaining)));
+ }
+ remaining.remove(added);
+ }
+
+ return sequenced;
+ }
+
+ static List<String> beanNamesOf(ArrayList<ModuleWithFixturesDescriptor> result) {
+ return result.stream().map(ModuleWithFixturesDescriptor::getBeanName).collect(Collectors.toList());
+ }
+
+ static ModuleWithFixturesDescriptor addNextModule(
+ final List<ModuleWithFixturesDescriptor> result,
+ final List<ModuleWithFixturesDescriptor> remaining,
+ final LinkedHashMap<String, ModuleWithFixturesDescriptor> moduleByName) {
+
+ for (ModuleWithFixturesDescriptor module : remaining) {
+ val numDependenciesNotYetEncountered =
+ module.getDependenciesByName().keySet().stream()
+ .map(moduleByName::get)
+ .filter(dependency -> !result.contains(dependency)) // ignore if already known about
+ .count();
+ if(numDependenciesNotYetEncountered == 0) {
+ result.add(module);
+ return module;
+ }
+ }
+ return null;
+ }
+
@EventListener(ContextRefreshedEvent.class)
public void onContextRefreshed(ContextRefreshedEvent event) {
log.info("onContextRefreshed");