Writing a simple Spring example using Play! Framework

I am trying to configure Spring 1.0.1 module to work with Play! 1.2.1 .

First, I added the Spring module to dependencies.yml:

- play -> spring 1.0.1 

Then I added the following as per the documentation in application.conf:

 play.spring.component-scan=true 

Then I ran the following to load dependencies and update IntelliJ configuration:

 play deps --sync play idealize 

Now, when I return to IntelliJ, I see that spring -1.0.1 has been added to my list of project modules, which looks right. However, if I look at the dependencies for my project, it does not have cans located in the spring -1.0.1 / lib directory. If I try and annotate one of my classes with @Component, it will not be able to find it. However, if I manually add spring -1.0.1 / lib as a project dependency, it will find @Component just fine. Suppose you run something else so that my IntelliJ project recognizes the Spring libraries found in the module?

The second part of my question is about connecting a simple example and writing a test for it.

So, let's say I have a Job class as follows:

 @Component @Every("10min") public class MyJob extends Job { private @Inject Printer printer; @Override public void doJob() throws Exception { printer.print(); } } 

And the Printer class is as follows:

 @Component public class Printer { public void print() { System.out.println("foo"); } } 

First, does annotation look right? And secondly, how do I start writing a test that will call MyJob.doJob (), but enter another printer that will print a "bar" instead of "foo"?

Update: As mentioned by Aaron, I changed @Inject to @Autowired. In my test class, I have something like this:

 @Test public void testSomething() { MyJob job = play.modules.spring.Spring.getBeanOfType(MyJob.class); job.doJob(); ... } 

In this case, getBeanOfType fails:

 play.modules.spring.SpringException at play.modules.spring.Spring.getBean(Spring.java:11) at com.testing.JobTest.testSomething(MyJob.java:20) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20) at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28) at play.test.PlayJUnitRunner$StartPlay$1$1$1.execute(PlayJUnitRunner.java:73) at play.Invoker$Invocation.run(Invoker.java:265) at play.Invoker.invokeInThread(Invoker.java:67) at play.test.PlayJUnitRunner$StartPlay$1$1.evaluate(PlayJUnitRunner.java:68) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:76) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184) at org.junit.runners.ParentRunner.run(ParentRunner.java:236) at play.test.PlayJUnitRunner.run(PlayJUnitRunner.java:48) at org.junit.runner.JUnitCore.run(JUnitCore.java:157) at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:60) 

Update 2: Ok, now I got even more. It seems that even if I do a component scan, the Spring module still needs application-context.xml in the conf / directory (although it does not define beans).

Now I just need to figure out how to enter a different version of the Printer object that spits out "bar" instead of "foo".

Update 3: I replaced using @Autowired with @Resource (name = "printer"), and I annotated my production printer using @Component ("printer") and renamed it to RealPrinter and provided an interface:

 @Component("printer") public class RealPrinter implements Printer { public void print() { System.out.println("foo"); } } 

If I only have the above printer, the injection works fine. Now, if I create TestPrinter, I need the Play Spring Module to understand that I want to use TestPrinter and not RealPrinter when I execute the test class.

 @Component("printer") public class TestPrinter implements Printer { public void print() { System.out.println("bar"); } } 

However, since I have two components named "printer", the Play Spring Module throws the following exception:

 play.exceptions.UnexpectedException: Unexpected Error at play.Play.start(Play.java:491) at play.test.PlayJUnitRunner.<init>(PlayJUnitRunner.java:31) at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27) at java.lang.reflect.Constructor.newInstance(Constructor.java:513) at org.junit.internal.builders.AnnotatedBuilder.buildRunner(AnnotatedBuilder.java:31) at org.junit.internal.builders.AnnotatedBuilder.runnerForClass(AnnotatedBuilder.java:24) at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:57) at org.junit.internal.builders.AllDefaultPossibilitiesBuilder.runnerForClass(AllDefaultPossibilitiesBuilder.java:29) at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:57) at org.junit.internal.requests.ClassRequest.getRunner(ClassRequest.java:24) at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:66) at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:192) at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:60) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at com.intellij.rt.execution.application.AppMain.main(AppMain.java:115) Caused by: java.lang.IllegalStateException: Annotation-specified bean name 'printer' for bean class [com.testing.job.RealPrinter] conflicts with existing, non-compatible bean definition of same name and class [com.testing.job.TestPrinter] at org.springframework.context.annotation.ClassPathBeanDefinitionScanner.checkCandidate(ClassPathBeanDefinitionScanner.java:267) at org.springframework.context.annotation.ClassPathBeanDefinitionScanner.doScan(ClassPathBeanDefinitionScanner.java:208) at org.springframework.context.annotation.ClassPathBeanDefinitionScanner.scan(ClassPathBeanDefinitionScanner.java:180) at play.modules.spring.SpringPlugin.onApplicationStart(SpringPlugin.java:98) at play.plugins.PluginCollection.onApplicationStart(PluginCollection.java:408) at play.Play.start(Play.java:463) ... 19 more 

As you can see, the reason for the exception is that there are now two printers with the same name.

+4
source share
2 answers

Ok, I came up with a solution that works for me. So, to write a test that introduces the layout / test version of the bean, I did the following:

 @Test public void testSomething() { GenericApplicationContext context = SpringPlugin.applicationContext; GenericBeanDefinition definition = new GenericBeanDefinition(); definition.setBeanClass(TestPrinter.class); definition.setAutowireCandidate(true); context.registerBeanDefinition("printer", definition); MyJob job = new MyJob(); job.doJob(); } 

Then I had to change MyJob as the root β€œinjector” of the things he needed:

 public class MyJob extends Job { public void doJob() throws Exception { Printer printer = Spring.getBeanOfType(Printer.class); printer.print(); } } 

TestPrinter no longer needs to be annotated with @Component, as the test method programmatically registers a test bean printer and thereby overrides the production bean printer.

Thus, executing the testSomething () method will print a bar. If I delete the registerBeanDefinition material, this will cause the message "foo" to be printed.

I'm not quite sure that this is the most convenient way to input test materials using the Play Spring module, but at least I can do what I want now.

+1
source

I did not try to use Play! and Spring together, but the documentation says that it does not support @Inject annotation:

http://www.playframework.org/modules/spring-1.0.1/home#ajavax.inject.Injectsupporta

You must use the @Autowired annotation. Again, I did not do this, but you can use @Qualifier with it to use different instances of the component.

0
source

All Articles