Let's say I have interface Bar:
public interface Bar {
void lengthyOperation ();
}
and it's implementation Foo:
#Service
public class Foo implements Bar {
void lengthyOperation () {
// lengthy operation implementation
}
}
I also have a singleton class called MyClass:
public class MyClass implements Runnable {
#Autowired private final Bar bar;
private final Thread thread;
private static MyClass instance;
private MyClass () {
thread = new Thread (this);
thread.start();
}
public static MyClass getInstance () {
if (instance == null) instance = new MyClass();
return instance;
}
public void run() {
while (true) {
bar.lengthyOperation();
Thread.sleep(5000);
}
}
}
How can I inject Bar into MyClass using #Autowired annotation (or any other way if possible)? I tried with #Autowired private final Bar bar; but it's always null;
If that can't be achieved, is there a way to prevent calling #Autowired constructor twice? If you don't know what I mean let me show you. This code:
#Controller
public class MyClass implements Runnable {
private final Bar bar;
#Autowired
public MyClass (Bar bar) {
this.bar = bar;
thread = new Thread (this);
thread.start();
}
public void run() {
System.out.println("New thread...");
while (true) {
bar.lengthyOperation();
Thread.sleep(5000);
}
}
}
would print out "New thread..." two times in console.
Maybe (probably) there is more gracious way of doing this, but I don't know about it... Any help would be appreciated!
Thank you!
EDIT #1 dimoniy asked how I make instance of my class. Basically, instance of MyClass has to be created on WebApp startup, so I used this code:
#Component
public class StartMyClass implements ApplicationListener<ApplicationEvent> {
public void onApplicationEvent(ApplicationEvent e) {
MyClass.getInstance();
}
}
How do you create your instance of MyClass?
The #Autowired does not work because your MyClass instance is not managed by Spring. You need to create MyClass instance in your Java/XML spring configuration or annotate it with #Component annotation and make sure that MyClass's package is scannable by spring.
Your annotation with #Controller is not correct since your class is clearly not a controller...
For example:
#Configuration
public class MiscConfiguration {
#Bean
public MyClass myClass() {
return new MyClass();//Will be created/managed by Spring, #Autowired will work
}
}
Related
I am trying to autowire multiple services (around 10-15) in a class having static methods and came across a solution mentioned in this post about using #Autowired constructor. Can we use constructor #Autowired approach for multiple classes as well?
For example, suppose I have two classes Foo1 and Foo2. Can I use the single constructor for both classes like
#Component
public class Boo {
private static Foo1 foo1;
private static Foo2 foo2;
#Autowired
public Boo(Foo1 foo1, Foo2 foo2) {
Boo.foo1 = foo1;
Boo.foo2 = foo2;
}
public static void randomMethod() {
foo1.doStuff();
foo2.doSomeOtherStuff();
}
}
Or is there any other way to achieve this ?
Spring + static is a very bad idea.
I suggest making the randomMethod() not static and then inject Boo everywhere you earlier had to call the static method. E.g change this:
class A {
public void run() {
Boo.randomMethod();
}
}
To this:
#Component
public class A {
private final Boo boo;
#Autowired
public A(Boo boo) {
this.boo = boo;
}
public void run() {
boo.randomMethod();
}
}
This construct is the spring intended way, and I suggest you to use it.
I want to test a method which creates an object of another class using it's parameterized constructor. Even though I've mocked the constructor of MyClass, it makes the third party library which is in constructor implementation and results in the error. I'm using Mockito/PowerMockito.
public class MyClass{
private MyObj obj;
MyClass (String profile)
{
//some 3rd party library call
obj = thridPartyLib.someMethod(profile);
}
public String someMethod(){
return obj.someExternalCall();
}
}
Class which I want to test
public class ClassTobeTested{
public void execute(){
//some code
// ......
MyClass myClass = new MyClass(profile);
myclass.someMethod();
}
}
What I tried so far - classUnderTest.execute() ends up calling the thridPartyLib.someMethod(profile); which is part of MyClass constructor.
#RunWith(PowerMockRunner.class)
#PrepareForTest(MyClass.class)
public class ClassTobeTestedTest {
private MyClass mockMyClass;
private ClassTobeTested classUnderTest;
#Before
public void init() {
classUnderTest = new ClassTobeTested();
mockMyClass = PowerMockito.mock(MyClass.class);
}
#Test
public void testExecute(){
PowerMockito.whenNew(MyClass.class)
.withArguments(Mockito.any())
.thenReturn(mockMyClass);
classUnderTest.execute();
}
}
Your code will work only if you are working with a spy or mock of classUnderTest. Try this. This should work
#RunWith(PowerMockRunner.class)
#PrepareForTest( {MyClass.class, ClassTobeTested.class })
public class ClassTobeTestedTest {
private MyClass mockMyClass;
private ClassTobeTested classUnderTest;
#Before
public void init() {
classUnderTest = spy(new ClassTobeTested());
mockMyClass = PowerMockito.mock(MyClass.class);
}
#Test
public void testExecute() throws Exception {
PowerMockito.whenNew(MyClass.class)
.withArguments(Mockito.any())
.thenReturn(mockMyClass);
classUnderTest.execute();
}
}
The pain might suggest another approach. Consider injecting a Factory into ClassTobeTested which knows how to create an instance of MyObj. For example:
class MyObjFactory {
MyObj create(String profile) {
return new MyClass(profile);
}
}
then
public class ClassTobeTested {
private final MyObjFactory factory;
public ClassTobeTested(MyObjFactory factory) {
this.factory = factory;
}
public void execute(){
//some code
// ......
// MyClass myClass = new MyClass(profile);
MyClass myClass = factory.create(profile);
myclass.someMethod();
}
}
so the unit test becomes simpler with only having to mock the Factory and have it return a mocked MyClass instance. Then it's simple to verify myclass.someMethod() was invoked as expected.
How to test a class which depends on Provider<>?
Please see the code below.
class ToTest {
#Inject
Provider<Processor> processorProvider;
public buildData() {
processorProvider.get().process();
}
class ProcessorProviderImpl implements Provider<Processor> {
#Inject
private Handler someHandler;
public Processor get() {
return new MyProcessor(somehandler)
}
}
public static class TestModule extends JukitoModule {
#Override
protected void configureTest() {
bind(Processor.class).toProvider(
ProcessorInstanceProviderImpl.class);
bindMock(SubHandler.class).in(TestSingleton.class);
}
}
class Handler {
#Inject
private SubHandler subHandler; // this is singleton instance
}
}
So when I mock subHandler it doesn't work and when I run unit test I am getting a NullPointerException where subHandler.handle() is getting called.
You can use Providers.of() to initialize processorProvider with a provider of your collaborator instance.
https://google.github.io/guice/api-docs/latest/javadoc/index.html?com/google/inject/util/Providers.html
test = new ToTest();
test.processorProvider = Providers.of(processorMock);
Here's my code:
// Groovy
interface MyMapper {
Buzz toBuzz(Fizz fizz);
}
class MyMapperImpl implements MyMapper {
#Named("SIMPLE_FOOBAR")
Foobar foobar;
MyMapperImpl(Foobar foobar) {
super();
this.foobar = foobar;
}
#Override
Buzz toBuzz(Fizz fizz) {
// ...etc.
}
}
class Whistlefeather {
MyMapper mapper;
Whistlefeather(MyMapper mapper) {
super();
this.mapper = mapper;
}
void doSomething(Fink fink) {
Fizz fizz = getSomehow(fink);
Buzz buzz = mapper.toBuzz(fizz);
// Do something with 'buzz'...
}
}
class ApplicationMain {
Whistlefeather whistlefeather;
#Inject
ApplicationMain(Whistlefeather whistlefeather) {
super();
this.whistlefeather = whistlefeather;
}
static void main(String[] args) {
Injector injector = Guice.createInjector(new ApplicationModule());
ApplicationMain appMain = injector.getInstance(ApplicationMain);
appMain.run();
}
void run() {
whistlefeather.doSomething(new Fink());
}
}
Here's my Guice module:
class ApplicationModule extends AbstractModule {
#Override
protected void configure() {
// I have to name the Foobars because in reality there will be
// *many* of them, each configured slightly different.
bind(Foobar.class).annotatedWith(Names.named("SIMPLE_FOOBAR"))
.toInstance(new Foobar(true, true, false, 103, "yee haw"));
bind(MyMapper.class).to(MyMapperImpl);
}
}
Here's my exception:
Could not find a suitable constructor in com.me.myapp.MyMapperImpl.
Classes must have either one (and only one) constructor annotated
with #Inject or a zero-argument constructor that is not private.
My understanding was that I only need to annotate constructors with #Inject if I would be directly calling them through the Injector#getInstance(...) method. Since I do this with ApplicationMain, which contains a reference to Whistlefeather, which contains a reference to MyMapper, I didn't think I would have to annotate the MyMapperImpl constructor.
Any ideas as to where I'm going awry here?
In order for Guice to create any object, it has to know which constructor to use. This is true all the way down the Object Graph.
Consider the following code:
public interface Something { }
public class SomethingImpl implements Something {
private final String data;
public SomethingImpl(String data) {
this.data = data;
}
public SomethingImpl(Integer data) {
this.data = data.toString();
}
}
public class AnotherClass {
private final Something something;
#Inject
public AnotherClass(Something something) {
this.something = something;
}
}
public class MyModule extends AbstractModule {
#Override
protected void configure() {
bind(Something.class).to(SomethingImpl.class);
bind(String.class).toInstance("Hello!");
bind(Integer.class).toInstance(50);
}
}
In this scenario, how is Guice supposed to know which constructor to use in SomethingImpl? If you were the author of Guice, how would you write it?
Obviously, you can't answer, because it's impossible. There has to be some sort of mechanism to tell Guice which constructor to use, regardless of whether or not it's called by Injector.getInstance() or not; that's why you have to annotate at least one constructor. Guice will use a no-argument constructor by default if one is specified, but if there isn't one, Guice doesn't know what to do.
I'm trying to get field injecting to work in google-gin, but when I call TestClass.test() the injected field is null. What am I doing wrong? According to the docs field injection should be really straight forward. Is there anything I'm missing in the ContextModule class?
public class MainEntry implements EntryPoint {
private final ContextInjector injector = GWT.create(ContextInjector.class);
#Override
public void onModuleLoad() {
injector.getAppMain();
}
}
#GinModules(ContextModule.class)
public interface ContextInjector extends Ginjector {
AppMain getAppMain();
}
public class MyLogger {
}
public class ContextModule extends AbstractGinModule {
#Override
protected void configure() {
bind(MyLogger.class).in(Singleton.class);
}
}
public class AppMain {
#Inject
AppMain(MyLogger logger) {
// logger is injected properly here
new TestClass().test();
}
}
public class TestClass {
#Inject
private MyLogger logger;
public void test() {
// logger is null here!
}
}
Your TestClass is not managed by GIN, so GIN won't inject anything in it. You have to either let GIN instantiate TestClass (e.g. change MyLogger to TestClass in your AppMain constructor, and call test() on the given instance), or ask GIN to inject an existing TestClass instance's members (add a method to your Ginjector that takes a TestClass as argument, when called, it'll inject fields and methods of the passed-in instance).