changeset 0:64e2ebad3366

Import des plain Spring DI playground
author Dirk Olmes <dirk.olmes@codedo.de>
date Tue, 11 Aug 2020 16:05:44 +0200
parents
children 60afb461bf6c
files .hgignore spring-di-playground/pom.xml spring-di-playground/src/test/java/de/comline/spring/ClasspathScanningTest.java spring-di-playground/src/test/java/de/comline/spring/ConfigurationTest.java spring-di-playground/src/test/java/de/comline/spring/QualifierTest.java spring-di-playground/src/test/java/de/comline/spring/model/ActionMovieCatalog.java spring-di-playground/src/test/java/de/comline/spring/model/ActionMovieLister.java spring-di-playground/src/test/java/de/comline/spring/model/ComedyMovieCatalog.java spring-di-playground/src/test/java/de/comline/spring/model/MovieCatalog.java spring-di-playground/src/test/java/de/comline/spring/model/scanning/ActionMovieCatalogComponent.java spring-di-playground/src/test/java/de/comline/spring/model/scanning/ComedyMovieCatalogComponent.java
diffstat 11 files changed, 314 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.hgignore	Tue Aug 11 16:05:44 2020 +0200
@@ -0,0 +1,4 @@
+.classpath
+.project
+.settings
+target
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spring-di-playground/pom.xml	Tue Aug 11 16:05:44 2020 +0200
@@ -0,0 +1,50 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+	<groupId>de.comline</groupId>
+	<artifactId>spring-di-playground</artifactId>
+	<version>0.0.1-SNAPSHOT</version>
+	<name>Spring DI container playground</name>
+
+	<properties>
+		<jdk.version.source>1.8</jdk.version.source>
+		<jdk.version.target>1.8</jdk.version.target>
+	</properties>
+
+	<build>
+		<plugins>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-compiler-plugin</artifactId>
+				<version>3.8.1</version>
+				<configuration>
+					<verbose>true</verbose>
+					<source>${jdk.version.source}</source>
+					<target>${jdk.version.target}</target>
+				</configuration>
+			</plugin>
+		</plugins>
+	</build>
+
+	<dependencies>
+		<dependency>
+			<groupId>org.springframework</groupId>
+			<artifactId>spring-context</artifactId>
+			<version>5.1.14.RELEASE</version>
+		</dependency>
+
+		<dependency>
+			<groupId>org.junit.jupiter</groupId>
+			<artifactId>junit-jupiter</artifactId>
+			<version>5.6.2</version>
+			<scope>test</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.hamcrest</groupId>
+			<artifactId>hamcrest</artifactId>
+			<version>2.2</version>
+			<scope>test</scope>
+		</dependency>
+	</dependencies>
+</project>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spring-di-playground/src/test/java/de/comline/spring/ClasspathScanningTest.java	Tue Aug 11 16:05:44 2020 +0200
@@ -0,0 +1,74 @@
+package de.comline.spring;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.fail;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
+import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.ComponentScan.Filter;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.FilterType;
+
+import de.comline.spring.model.MovieCatalog;
+import de.comline.spring.model.scanning.ActionMovieCatalogComponent;
+
+public class ClasspathScanningTest {
+	@Test
+	@DisplayName("Scanning explicit packages")
+	public void classpathScanning() {
+		try (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext("de.comline.spring.model.scanning")) {
+			assertThrows(NoUniqueBeanDefinitionException.class, () -> {
+				context.getBean(MovieCatalog.class);
+				fail("Classpath scanning must have detected both implementations of the MovieCatalog interface");
+			});
+		}
+	}
+
+	@Test
+	@DisplayName("Scanning by configuration")
+	public void explicitConfiguration() {
+		try (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ScanningConfiguration.class)) {
+			assertThrows(NoUniqueBeanDefinitionException.class, () -> {
+				context.getBean(MovieCatalog.class);
+				fail("Classpath scanning must have detected both implementations of the MovieCatalog interface");
+			});
+		}
+	}
+
+	@Test
+	@DisplayName("Scanning by configuration with filter")
+	public void configurationWithFilter() {
+		try (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(FilteredScanningConfiguration.class)) {
+			MovieCatalog catalog = context.getBean(MovieCatalog.class);
+			assertThat(catalog.getCategory(), is("Comedy"));
+		}
+	}
+
+	/**
+	 * Note: class may not be final.<br/>
+	 * Note: class must have a default constructor which is package protected at
+	 * least
+	 */
+	@Configuration
+	@ComponentScan(basePackages = "de.comline.spring.model.scanning")
+	private static class ScanningConfiguration {
+		@SuppressWarnings("unused")
+		ScanningConfiguration() {
+			super();
+		}
+	}
+
+	@Configuration
+	@ComponentScan(basePackages = "de.comline.spring.model.scanning", excludeFilters = @Filter(type = FilterType.ASSIGNABLE_TYPE, classes = ActionMovieCatalogComponent.class))
+	private static class FilteredScanningConfiguration {
+		@SuppressWarnings("unused")
+		FilteredScanningConfiguration() {
+			super();
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spring-di-playground/src/test/java/de/comline/spring/ConfigurationTest.java	Tue Aug 11 16:05:44 2020 +0200
@@ -0,0 +1,64 @@
+package de.comline.spring;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.fail;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
+import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import de.comline.spring.model.ActionMovieCatalog;
+import de.comline.spring.model.ComedyMovieCatalog;
+import de.comline.spring.model.MovieCatalog;
+
+public class ConfigurationTest {
+	@Test
+	@DisplayName("Explicit bean configuration")
+	public void beansInConfiguration() {
+		try (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(BeansConfiguration.class)) {
+			MovieCatalog catalog = context.getBean(MovieCatalog.class);
+			assertThat(catalog.getCategory(), is("Comedy"));
+		}
+	}
+	
+	@Test
+	@DisplayName("Duplicate beans can be registered")
+	public void duplicateBeansInConfiguration() {
+		try (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(DuplicateBeansConfiguration.class)) {
+			assertThrows(NoUniqueBeanDefinitionException.class, () -> {
+				context.getBean(MovieCatalog.class);
+				fail("Configuration scanning must have detected both implementations of the MovieCatalog interface");
+			});
+		}
+	}
+	
+	@Configuration
+	private static class BeansConfiguration {
+		BeansConfiguration() {
+			super();
+		}
+		
+		@Bean
+		MovieCatalog defineMovieCatalog() {
+			return new ComedyMovieCatalog();
+		}
+	}
+	
+	@Configuration
+	private static class DuplicateBeansConfiguration extends BeansConfiguration {
+		@SuppressWarnings("unused")
+		DuplicateBeansConfiguration() {
+			super();
+		}
+		
+		@Bean
+		MovieCatalog duplicateMovieCatalog() {
+			return new ActionMovieCatalog();
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spring-di-playground/src/test/java/de/comline/spring/QualifierTest.java	Tue Aug 11 16:05:44 2020 +0200
@@ -0,0 +1,57 @@
+package de.comline.spring;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.is;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
+import org.springframework.context.ConfigurableApplicationContext;
+import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+
+import de.comline.spring.model.ActionMovieCatalog;
+import de.comline.spring.model.ActionMovieLister;
+import de.comline.spring.model.ComedyMovieCatalog;
+import de.comline.spring.model.MovieCatalog;
+
+public class QualifierTest {
+	@Test
+	@DisplayName("Requesting explicit interface type")
+	public void explicitType() {
+		try (ConfigurableApplicationContext context = new AnnotationConfigApplicationContext(ActionMovieCatalog.class, ComedyMovieCatalog.class)) {
+			MovieCatalog action = context.getBean(ActionMovieCatalog.class);
+			assertThat(action.getCategory(), is("Action"));
+		}
+	}
+
+	@Test
+	@DisplayName("Qualifier can be specified at source")
+	public void qualifierAtSource() {
+		// Note how we add multiple interface implementations to the context
+		try (ConfigurableApplicationContext context = new AnnotationConfigApplicationContext(ActionMovieCatalog.class, ComedyMovieCatalog.class, ActionMovieLister.class)) {
+			ActionMovieLister lister = context.getBean(ActionMovieLister.class);
+			assertThat(lister.toString(), containsString("Action"));
+		}
+	}
+
+	@Test
+	@DisplayName("Binding only a single interface implementation")
+	public void singleImplementationOfInterface() {
+		try (ConfigurableApplicationContext context = new AnnotationConfigApplicationContext(ComedyMovieCatalog.class)) {
+			MovieCatalog catalog = context.getBean(MovieCatalog.class);
+			assertThat(catalog.getCategory(), is("Comedy"));
+		}
+	}
+
+	@Test
+	@DisplayName("Multiple implementations of the same interface cannot be injected")
+	public void multipleInterfaceImplementations() {
+		try (ConfigurableApplicationContext context = new AnnotationConfigApplicationContext(ActionMovieCatalog.class, ComedyMovieCatalog.class)) {
+			assertThrows(NoUniqueBeanDefinitionException.class, () -> {
+				context.getBean(MovieCatalog.class);
+			});
+		}
+	}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spring-di-playground/src/test/java/de/comline/spring/model/ActionMovieCatalog.java	Tue Aug 11 16:05:44 2020 +0200
@@ -0,0 +1,11 @@
+package de.comline.spring.model;
+
+import org.springframework.beans.factory.annotation.Qualifier;
+
+@Qualifier(value = "Action")
+public class ActionMovieCatalog implements MovieCatalog {
+	@Override
+	public String getCategory() {
+		return "Action";
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spring-di-playground/src/test/java/de/comline/spring/model/ActionMovieLister.java	Tue Aug 11 16:05:44 2020 +0200
@@ -0,0 +1,20 @@
+package de.comline.spring.model;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+
+public class ActionMovieLister {
+	/**
+	 * The qualifier is specified at the source - which is almost never what you
+	 * want. Note however, how the qualifier mentioned here matches the qualifier
+	 * annotation value on the injected class (ActionMovieCatalog).
+	 */
+	@Autowired
+	@Qualifier(value = "Action")
+	private MovieCatalog actionMovies;
+
+	@Override
+	public String toString() {
+		return "Listing of " + actionMovies.getCategory() + " films";
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spring-di-playground/src/test/java/de/comline/spring/model/ComedyMovieCatalog.java	Tue Aug 11 16:05:44 2020 +0200
@@ -0,0 +1,11 @@
+package de.comline.spring.model;
+
+import org.springframework.beans.factory.annotation.Qualifier;
+
+@Qualifier(value = "Comedy")
+public class ComedyMovieCatalog implements MovieCatalog {
+	@Override
+	public String getCategory() {
+		return "Comedy";
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spring-di-playground/src/test/java/de/comline/spring/model/MovieCatalog.java	Tue Aug 11 16:05:44 2020 +0200
@@ -0,0 +1,5 @@
+package de.comline.spring.model;
+
+public interface MovieCatalog {
+	public String getCategory();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spring-di-playground/src/test/java/de/comline/spring/model/scanning/ActionMovieCatalogComponent.java	Tue Aug 11 16:05:44 2020 +0200
@@ -0,0 +1,9 @@
+package de.comline.spring.model.scanning;
+
+import org.springframework.stereotype.Component;
+
+import de.comline.spring.model.ActionMovieCatalog;
+
+@Component
+public class ActionMovieCatalogComponent extends ActionMovieCatalog {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spring-di-playground/src/test/java/de/comline/spring/model/scanning/ComedyMovieCatalogComponent.java	Tue Aug 11 16:05:44 2020 +0200
@@ -0,0 +1,9 @@
+package de.comline.spring.model.scanning;
+
+import org.springframework.stereotype.Component;
+
+import de.comline.spring.model.ComedyMovieCatalog;
+
+@Component
+public class ComedyMovieCatalogComponent extends ComedyMovieCatalog {
+}