From 77e968bccd2a59739348c23e04a2edd7eed231f6 Mon Sep 17 00:00:00 2001 From: Dave Syer Date: Mon, 14 Apr 2014 17:33:48 +0100 Subject: [PATCH] Initial experiments --- .gitignore | 19 +++ pom.xml | 57 +++++++ src/main/java/demo/Application.java | 16 ++ src/main/resources/application.properties | 0 .../demo/AbstractCompleteWiringTests.java | 47 ++++++ src/test/java/demo/GuiceWiringTests.java | 39 +++++ src/test/java/demo/HybridWiringTests.java | 42 +++++ .../demo/ModuleRegistryConfiguration.java | 69 +++++++++ src/test/java/demo/SimpleWiringTests.java | 59 ++++++++ src/test/java/demo/SpringInjector.java | 143 ++++++++++++++++++ src/test/java/demo/SpringWiringTests.java | 44 ++++++ 11 files changed, 535 insertions(+) create mode 100644 .gitignore create mode 100644 pom.xml create mode 100644 src/main/java/demo/Application.java create mode 100644 src/main/resources/application.properties create mode 100644 src/test/java/demo/AbstractCompleteWiringTests.java create mode 100644 src/test/java/demo/GuiceWiringTests.java create mode 100644 src/test/java/demo/HybridWiringTests.java create mode 100644 src/test/java/demo/ModuleRegistryConfiguration.java create mode 100644 src/test/java/demo/SimpleWiringTests.java create mode 100644 src/test/java/demo/SpringInjector.java create mode 100644 src/test/java/demo/SpringWiringTests.java diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e4dad1e --- /dev/null +++ b/.gitignore @@ -0,0 +1,19 @@ +#*# +.#* +*~ +_site/ +*/src/META-INF/ +*/src/main/java/META-INF/ +bin/ +target/ +.classpath +.project +.DS_Store +.settings/ +*.iml +*.iws +*.ipr +.idea/ +code/ +cargo-installs/ +atlassian-ide-plugin.xml diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..2af52a3 --- /dev/null +++ b/pom.xml @@ -0,0 +1,57 @@ + + + 4.0.0 + + org.demo + demo + 0.0.1-SNAPSHOT + + scratch + Demo project + + + org.springframework.boot + spring-boot-starter-parent + 1.0.0.RELEASE + + + + + org.springframework.boot + spring-boot-starter + + + com.google.inject + guice + 3.0 + compile + + + cglib + org.sonatype.sisu.inject + + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + demo.Application + 1.7 + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + \ No newline at end of file diff --git a/src/main/java/demo/Application.java b/src/main/java/demo/Application.java new file mode 100644 index 0000000..7ac985b --- /dev/null +++ b/src/main/java/demo/Application.java @@ -0,0 +1,16 @@ +package demo; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; + +@Configuration +@ComponentScan +@EnableAutoConfiguration +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties new file mode 100644 index 0000000..e69de29 diff --git a/src/test/java/demo/AbstractCompleteWiringTests.java b/src/test/java/demo/AbstractCompleteWiringTests.java new file mode 100644 index 0000000..edb0438 --- /dev/null +++ b/src/test/java/demo/AbstractCompleteWiringTests.java @@ -0,0 +1,47 @@ +package demo; + +import static org.junit.Assert.assertNotNull; + +import javax.inject.Inject; + +import org.junit.Before; +import org.junit.Test; + +import com.google.inject.Injector; + +public abstract class AbstractCompleteWiringTests { + + private Injector injector; + + @Before + public void init() { + injector = createInjector(); + } + + protected abstract Injector createInjector(); + + @Test + public void getInstanceUnbound() { + assertNotNull(injector.getInstance(Foo.class)); + } + + @Test + public void getInstanceBound() { + assertNotNull(injector.getInstance(Service.class)); + } + + interface Service { + } + + protected static class MyService implements Service { + } + + public static class Foo { + + @Inject + public Foo(Service service) { + } + + } + +} diff --git a/src/test/java/demo/GuiceWiringTests.java b/src/test/java/demo/GuiceWiringTests.java new file mode 100644 index 0000000..050e5fe --- /dev/null +++ b/src/test/java/demo/GuiceWiringTests.java @@ -0,0 +1,39 @@ +/* + * Copyright 2013-2014 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 + * + * http://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 demo; + +import com.google.inject.AbstractModule; +import com.google.inject.Guice; +import com.google.inject.Injector; + +/** + * @author Dave Syer + * + */ +public class GuiceWiringTests extends AbstractCompleteWiringTests { + + @Override + protected Injector createInjector() { + Injector app = Guice.createInjector(new TestConfig()); + return app; + } + + public static class TestConfig extends AbstractModule { + @Override + protected void configure() { + bind(Service.class).to(MyService.class); + } + } + +} diff --git a/src/test/java/demo/HybridWiringTests.java b/src/test/java/demo/HybridWiringTests.java new file mode 100644 index 0000000..bd147c5 --- /dev/null +++ b/src/test/java/demo/HybridWiringTests.java @@ -0,0 +1,42 @@ +/* + * Copyright 2013-2014 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 + * + * http://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 demo; + +import org.springframework.context.annotation.AnnotationConfigApplicationContext; + +import com.google.inject.AbstractModule; +import com.google.inject.Injector; + +/** + * @author Dave Syer + * + */ +public class HybridWiringTests extends AbstractCompleteWiringTests { + + @Override + protected Injector createInjector() { + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); + context.register(TestConfig.class, ModuleRegistryConfiguration.class); + context.refresh(); + return new SpringInjector(context); + } + + public static class TestConfig extends AbstractModule { + @Override + protected void configure() { + bind(Service.class).to(MyService.class); + } + } + +} diff --git a/src/test/java/demo/ModuleRegistryConfiguration.java b/src/test/java/demo/ModuleRegistryConfiguration.java new file mode 100644 index 0000000..c65a60a --- /dev/null +++ b/src/test/java/demo/ModuleRegistryConfiguration.java @@ -0,0 +1,69 @@ +/* + * Copyright 2013-2014 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 + * + * http://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 demo; + +import java.util.Collections; +import java.util.List; +import java.util.Map.Entry; + +import javax.annotation.PostConstruct; + +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.ObjectFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import com.google.inject.Binding; +import com.google.inject.Guice; +import com.google.inject.Injector; +import com.google.inject.Key; +import com.google.inject.Module; +import com.google.inject.Provider; + +@Configuration +public class ModuleRegistryConfiguration { + + @Autowired + private ConfigurableListableBeanFactory beanFactory; + + @Autowired(required=false) + private List modules = Collections.emptyList(); + + private Injector injector; + + @Bean + public Injector injector() { + return injector; + } + + @PostConstruct + public void init() { + injector = Guice.createInjector(modules); + for (Entry, Binding> entry : injector.getBindings().entrySet()) { + if (entry.getKey().getTypeLiteral().getRawType().equals(Injector.class)) { + continue; + } + final Provider provider = entry.getValue().getProvider(); + beanFactory.registerResolvableDependency(entry.getKey().getTypeLiteral().getRawType(), new ObjectFactory() { + @Override + public Object getObject() throws BeansException { + return provider.get(); + } + }); + } + } + +} \ No newline at end of file diff --git a/src/test/java/demo/SimpleWiringTests.java b/src/test/java/demo/SimpleWiringTests.java new file mode 100644 index 0000000..ab1537f --- /dev/null +++ b/src/test/java/demo/SimpleWiringTests.java @@ -0,0 +1,59 @@ +package demo; + +import static org.junit.Assert.assertNotNull; + +import javax.inject.Inject; + +import org.junit.Test; +import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; + +import com.google.inject.AbstractModule; +import com.google.inject.Guice; +import com.google.inject.Injector; + +public class SimpleWiringTests { + + @Test + public void guiceyFoo() { + Injector app = Guice.createInjector(new TestConfig()); + assertNotNull(app.getInstance(Foo.class)); + } + + @Test + public void springyFoo() { + @SuppressWarnings("resource") + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TestConfig.class, MyService.class); + context.getDefaultListableBeanFactory().registerBeanDefinition(Foo.class.getSimpleName(), new RootBeanDefinition(Foo.class)); + assertNotNull(context.getBean(Foo.class)); + } + + @Test + public void hybridFoo() { + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TestConfig.class, ModuleRegistryConfiguration.class); + Injector app = new SpringInjector(context); + assertNotNull(app.getInstance(Foo.class)); + } + + protected static class TestConfig extends AbstractModule { + @Override + protected void configure() { + bind(Service.class).to(MyService.class); + } + } + + interface Service { + } + + protected static class MyService implements Service { + } + + protected static class Foo { + + @Inject + public Foo(Service service) { + } + + } + +} diff --git a/src/test/java/demo/SpringInjector.java b/src/test/java/demo/SpringInjector.java new file mode 100644 index 0000000..cb17e68 --- /dev/null +++ b/src/test/java/demo/SpringInjector.java @@ -0,0 +1,143 @@ +/* + * Copyright 2013-2014 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 + * + * http://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 demo; + +import java.lang.annotation.Annotation; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.context.support.GenericApplicationContext; + +import com.google.inject.Binding; +import com.google.inject.Injector; +import com.google.inject.Key; +import com.google.inject.MembersInjector; +import com.google.inject.Module; +import com.google.inject.Provider; +import com.google.inject.Scope; +import com.google.inject.TypeLiteral; +import com.google.inject.spi.TypeConverterBinding; + +public class SpringInjector implements Injector { + + private GenericApplicationContext context; + private Injector injector; + + public SpringInjector(GenericApplicationContext context) { + this.context = context; + if (context.getBeanNamesForType(Injector.class).length>0) { + injector = context.getBean(Injector.class); + } + } + + @Override + public void injectMembers(Object instance) { + + } + + @Override + public MembersInjector getMembersInjector(TypeLiteral typeLiteral) { + return null; + } + + @Override + public MembersInjector getMembersInjector(Class type) { + return null; + } + + @Override + public Map, Binding> getBindings() { + return null; + } + + @Override + public Map, Binding> getAllBindings() { + return null; + } + + @Override + public Binding getBinding(Key key) { + return null; + } + + @Override + public Binding getBinding(Class type) { + return null; + } + + @Override + public Binding getExistingBinding(Key key) { + return null; + } + + @Override + public List> findBindingsByType(TypeLiteral type) { + return null; + } + + @Override + public Provider getProvider(Key key) { + return null; + } + + @Override + public Provider getProvider(Class type) { + return null; + } + + @Override + public T getInstance(Key key) { + return null; + } + + @Override + public T getInstance(Class type) { + if (context.getBeanNamesForType(type).length==0) { + if (injector!=null && injector.getExistingBinding(Key.get(type))!=null) { + return injector.getInstance(type); + } + // TODO: use prototype scope? + context.getDefaultListableBeanFactory().registerBeanDefinition(type.getSimpleName(), new RootBeanDefinition(type)); + } + return context.getBean(type); + } + + @Override + public Injector getParent() { + return null; + } + + @Override + public Injector createChildInjector(Iterable modules) { + return null; + } + + @Override + public Injector createChildInjector(Module... modules) { + return null; + } + + @Override + public Map, Scope> getScopeBindings() { + return null; + } + + @Override + public Set getTypeConverterBindings() { + return null; + } + +} \ No newline at end of file diff --git a/src/test/java/demo/SpringWiringTests.java b/src/test/java/demo/SpringWiringTests.java new file mode 100644 index 0000000..27578ca --- /dev/null +++ b/src/test/java/demo/SpringWiringTests.java @@ -0,0 +1,44 @@ +/* + * Copyright 2013-2014 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 + * + * http://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 demo; + +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import com.google.inject.Injector; + +/** + * @author Dave Syer + * + */ +public class SpringWiringTests extends AbstractCompleteWiringTests { + + @Override + protected Injector createInjector() { + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); + context.register(TestConfig.class); + context.refresh(); + return new SpringInjector(context); + } + + @Configuration + public static class TestConfig { + @Bean + public Service service() { + return new MyService(); + } + } + +}