I am a big fan of Play, and I use it in almost any project of mine nowadays. As one of my projects got bigger, though, I decided to include a DI solution. After a brief consideration between Spring and Guice, I stopped on Guice and added the Guice module for Play (http://www.playframework.com/modules/guice-1.0/home).
The problem with it, seems to be the fact that injection works for static fields only. This means that I will have to do stuff like:
#InjectSupport
public class MyService {
#Inject
static MyBean myBean;
}
from (http://java.dzone.com/articles/dependency-injection-play)
which scares me a bit, especially when it comes to testing. I mean, it is true that most of the DI solutions always try to inject singletons, for instance Spring creates a single instance of every bean and injects it, which is kind of the same at the end, but still. Should I have these concerns?
You definitely can perform Guice injection with Play.
You should not use the old Guice module (version 1.0). The tutorial you referred to is also using the old Guice, and old Play (version 1.2!)
Please take a look of the new Guice module (version 3.0) & Play (version 2.1.1)
http://www.playframework.com/documentation/2.1.1/JavaInjection
When you inject to an instance variable, you need to create controller dynamically
In your route file:
GET / #controllers.Application.index()
In your Global.java, you need to override getControllerInstance:
#Override
public <A> A getControllerInstance(Class<A> controllerClass) throws Exception {
return INJECTOR.getInstance(controllerClass);
}
In Play 1, you can easily combine normal Guice singletons with statically injected controller fields, the trick is getting the annotation imports correct.
In your play controllers, jobs & test classes that need static injection use the JSR330 annotation versions:
import javax.inject.Inject;
public class Application extends Controller {
#Inject private static MyService myService;
....
}
and for other classes that need #InjectSupport use JSR330/module imports:
import play.modules.guice.InjectSupport;
import javax.inject.Inject;
#InjectSupport
public class AnotherClass {
#Inject private static MyService myService;
}
For the actual (non-static) services instantiated by Guice library, you need to use the Guice annotation versions (note the com.google.inject package):
import com.google.inject.Inject;
import com.google.inject.Singleton;
#Singleton
public class MyService {
#Inject private AnotherService anotherService; // note non-static injection
}
You'll also need an empty Module to kick things off:
import com.google.inject.AbstractModule;
public class MainModule extends AbstractModule {
#Override
protected void configure() {}
}
This should also work for Guice classes created in other ways apart from #Singleton, such as #Provides, although I haven't tried this yet.
Related
I'm tasked with writing JUnit classes. To do this, I need to create an object that implements an interface that extends org.springframework.data.jpa.repository.JpaRepository, (called "KanjiRepo") yet no classes in this application actually implement KanjiRepo.
Rather than with new, all objects that implement KanjiRepo seem to be created via #Autowiring.
The KanjiRepo interface is a member of a package that has only interfaces, and they all extend org.springframework.data.jpa.repository.JpaRepository.
[question] I don't think I understand the problem. Can someone tell me if what I just said sounds correct. In my junit, do I also use #Autowire to create objects that implement the interfaces in the same package as KanjiRepo?Maintaining 2 separate Application Contexts will be needed as a last step?
I think Autowiring KanjiRepo is enough in your test class unless you annotate your repository as #Repository.
#Repository
public interface KanjiRepo extends JpaRepository....
If you have #Repository annotation on top of KanjiRepo and if you annototated your main class or configuration class to auto scan beans; spring would handle creating and autowiring beans succesfully.
Please check for component scan
#SpringBootApplication
// or #ComponentScan
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
And then, you can create your test class with the following code;
#Autowired
KanjiRepo repo;
#Test
public void testFindById() {
Kanji instance = repo.findById(0L);
assert.....
}
should be fine.
Can the application and JUnit share the same configuration files?
Actually, it is. But, if you do component scan, you don't have to worry that. Spring will handle where your bean is and it should autowire succesfully.
do I also use #Autowire to create objects that implement the interfaces in the same package as KanjiRepo?
Spring will do component scan and will find where your repository is, so, you don't have to worry that where you locate your repository.
I am using Quarkus for a little project and I got stuck in unit testing my classes using the tools that Quarkus offers.
The problem is, I used the following approach to mock som classes:
https://quarkus.io/guides/getting-started-testing#mock-support
Mocking my Dao or Service class would be a nice way in my opinion.
However Mocking my classes leads to the effect that when I inject my Service/Dao class that has to be tested, the container for sure injects the Mock implementation.
Is there a way to prevent that and use the real implementation class?
#ApplicationScoped
public class ExpenseDaoImpl implements ExpenseDao {
}
#Mock
#ApplicationScoped
public class ExpenseDaoMock implements ExpenseDao {
}
#QuarkusTest
class ExpenseDaoTest {
#Inject
private ExpenseDao expenseDao; //injects the mocked implementation
}
I just start learning Spring framework (i use version 4.3.0) and i thought that we need #Autowired to tell the framework when a class need injection.
However, i try this today:
#Component
public class CDPlayer implements MediaPlayer{
private CompactDisc cd;
//there are no #Autowired here
public CDPlayer(CompactDisc cd) {
this.cd = cd;
}
public void play() {
cd.play();
}
}
and it work perfectly fine with automatic wiring configuration:
#Configuration
#ComponentScan
public class CDPlayerConfigAuto {
}
So when i do really need to use #Autowired?
Since Spring 4.3 this is not necesary if your class has only one constructor.
So as of 4.3, you no longer need to specify an explicit injection
annotation in such a single-constructor scenario. This is particularly
elegant for classes which otherwise do not carry any container
annotations at all.
You can see here: (Implicit constructor injection for single-constructor scenarios)
https://spring.io/blog/2016/03/04/core-container-refinements-in-spring-framework-4-3
This is a new feature in Spring Boot 4.3. If you have only one constructor in the class, this constructor will be used to autowire the arguments. If you have more constructors or if you want to use setter or field injection, then you still need the #Autowired annotation.
We have decided to use Dependency Injection with JSR-330 annotations for our future modularization efforts, and have been very pleased with the first deliverable based on Guice 2 SVN.
Now we need to ensure and document through unit tests that the constructions we need, also work in Spring when configured programmatically (we want the same refactoring support as with Guice so no XML files). I have problems with #Provider and #Inject #Named("foo") String but I have made plain #Inject work with:
ApplicationContext ctx = new AnnotationConfigApplicationContext(LIBL_Object.class,
CORE_Provider.class);
this.object = ctx.getBean(LIBL_Object.class);
where LIBL_Object is the base class to be injected into, but the CORE_Provider does not register as I hoped within Spring.
The implementation of CORE_Provider is
package qa.jsr330.core;
import javax.inject.Provider;
public class CORE_Provider implements Provider<ProvidedInterface> {
#Override
public ProvidedInterface get() {
return new CORE_Provided();
}
}
and I want it injected into
package qa.jsr330.core;
import javax.inject.Inject;
public class LIBL_Object {
private ProvidedInterface provided;
public ProvidedInterface getProvided() {
return provided;
}
#Inject
public void setProvided(ProvidedInterface provided) {
this.provided = provided;
}
// Other stuff omitted.
}
Also we have found that we can pass configuration values very clearly using the #Named tag. This code looks like:
String hostname;
#Inject
public void setHostname(#Named("as400.hostname") String hostname) {
this.hostname = hostname;
}
where we can then register this string with Guice using
bindConstant().annotatedWith(Names.named("as400.hostname")).to(value);
So the two questions are:
How do I register the #Provider class with Spring 3 programatically?
How do I register a string constant with Spring 3 so that #Named selects it properly?
The short answer is: there is no such thing as programmatic configuration of Spring.
Despite the fact that both Spring and Guice support JSR-330 API and that Spring can be configured without XML now, their ideologies are still very different. Spring relies on static configuration, either in the form of XML files or annotated Java classes. Therefore straightforward attempt to adapt Guice-style configuration to Spring may produce difficulties.
Regarding the problem with Provider - Spring doesn't support javax.inject.Provider in the same way as toProvider() binding in Guice (by the way, this usage of Provider is not specified in JSR-330 docs). Therefore some Spring-specific annotations may be needed, for example
#Configuration
public class CORE_Provider implements Provider<ProvidedInterface> {
#Override #Bean
public ProvidedInterface get() {
return new CORE_Provided();
}
}
Binding value coming from the outside may be difficult due to static nature of Spring configuration. For example, in your case, it can be done like this:
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(IBL_Object.class);
ctx.register(CORE_Provider.class);
ctx.registerBeanDefinition("as400.hostname",
BeanDefinitionBuilder.rootBeanDefinition(String.class)
.addConstructorArgValue(value).getBeanDefinition());
ctx.refresh();
Let's say we have a class:
public class MyClass {
#Autowired private AnotherBean anotherBean;
}
Then we created an object of this class (or some other framework have created the instance of this class).
MyClass obj = new MyClass();
Is it possible to still inject the dependencies? Something like:
applicationContext.injectDependencies(obj);
(I think Google Guice has something like this)
You can do this using the autowireBean() method of AutowireCapableBeanFactory. You pass it an arbitrary object, and Spring will treat it like something it created itself, and will apply the various autowiring bits and pieces.
To get hold of the AutowireCapableBeanFactory, just autowire that:
private #Autowired AutowireCapableBeanFactory beanFactory;
public void doStuff() {
MyBean obj = new MyBean();
beanFactory.autowireBean(obj);
// obj will now have its dependencies autowired.
}
You can also mark your MyClass with #Configurable annotation:
#Configurable
public class MyClass {
#Autowired private AnotherClass instance
}
Then at creation time it will automatically inject its dependencies. You also should have <context:spring-configured/> in your application context xml.
Just got the same need and in my case it was already the logic inside non Spring manageable java class which had access to ApplicationContext. Inspired by scaffman.
Solved by:
AutowireCapableBeanFactory factory = applicationContext.getAutowireCapableBeanFactory();
factory.autowireBean(manuallyCreatedInstance);
I used a different approach. I had spring loaded beans that I wanted to call from my extended classes of a third-party library that created its own threads.
I used approach I found here https://confluence.jaytaala.com/display/TKB/Super+simple+approach+to+accessing+Spring+beans+from+non-Spring+managed+classes+and+POJOs
In the non-managed class:
{
[...]
SomeBean bc = (SomeBean) SpringContext.getBean(SomeBean.class);
[...]
bc.someMethod(...)
}
And then as a helper class in the main application:
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
#Component
public class SpringContext implements ApplicationContextAware
{
private static ApplicationContext context;
public static <T extends Object> T getBean(Class<T> beanClass)
{
return context.getBean(beanClass);
}
#Override
public void setApplicationContext(ApplicationContext context) throws BeansException
{
SpringContext.context = context;
}
}
I wanted to share my solution that follows the #Configurable approach as briefly mentioned in #glaz666 answer because
The answer by #skaffman is nearly 10 years old, and that does not mean not good enough or does not work
The answer by #glaz666 is brief and didn't really help me solve my problem but, did point me in the right direction
My setup
Spring Boot 2.0.3 with Spring Neo4j & Aop starts (which is irrelevant anyway)
Instantiate a bean when Spring Boot is ready using #Configurable approach (using ApplicationRunner)
Gradle & Eclipse
Steps
I needed to follow the steps below in order to get it working
The #Configurable(preConstruction = true, autowire = Autowire.BY_TYPE, dependencyCheck = false) to be placed on top of your Bean that is to be manually instantiated. In my case the Bean that is to be manually instantiated have #Autowired services hence, the props to above annotation.
Annotate the Spring Boot's main XXXApplicaiton.java (or the file that is annotated with #SpringBootApplication) with the #EnableSpringConfigured and #EnableLoadTimeWeaving(aspectjWeaving=AspectJWeaving.ENABLED)
Add the dependencies in your build file (i.e. build.gradle or pom.xml depending on which one you use) compile('org.springframework.boot:spring-boot-starter-aop') and compile('org.springframework:spring-aspects:5.0.7.RELEASE')
New+up your Bean that is annotated with #Configurable anywhere and its dependencies should be autowired.
*In regards to point #3 above, I am aware that the org.springframework.boot:spring-boot-starter-aop transitively pulls the spring-aop (as shown here mavencentral) but, in my case the Eclipse failed to resolve the #EnableSpringConfigured annotations hence, why I explicitly added the spring-aop dependency in addition to the starter. Should you face the same issue, just declare the dependency or go on adventure of figuring out
Is there a version conflict
Why the org.springframework.context.annotation.aspect.* is not available
Is your IDE setup properly
Etc etc.
This worked for me:
#Configuration
public class AppConfig {
#Bean
public TransferService transferService() {
return new TransferServiceImpl();
}
}
See more information: https://docs.spring.io/spring-javaconfig/docs/1.0.0.m3/reference/html/creating-bean-definitions.html
Found the following way useful for my use case. Sharing here for reference, credit goes to the blogger entirely. This creates a static field and populates that from Spring and then provides a public static method which returns the field populated above.
https://sultanov.dev/blog/access-spring-beans-from-unmanaged-objects/