I know from this solution I can autowired static fields in spring.
#Component
public class AdminUtil {
private static IAirportService airportService;
#Autowired
public AdminUtil(IAirportService portService) {
AdminUtil.airportService = portService;
}
...
}
But sonar says: Static fields should not be updated in constructors (RSPEC-3010)
Is there any alternate way to autowired static fields in spring? Or do I ignore this?
Spring's idea is that Components get instantiated once by default and reused throughout the application. This should be save as long as the components don't hold state.
Considering your code sample the easiest solution would be to not make the airportService static.
Related
I was wondering how to do dependency injection in the most effective way inside my code.
I have this code:
#Configuration
public class SomeName {
#Autowired
private Other other;
#Bean
public void method() {
other.someMethod();
// some code
}
}
Can this code be changed into the following code(other will be used only inside this function)?
#Configuration
public class SomeName {
#Bean
public void method(Other other) {
other.someMethod();
// some code
}
}
You should avoid #Autowired if possible and inject using a constructor or method.
Starting with Java 9 and java modules (project jigsaw) there are some strict rules that make it harder for your framework to change the values of a private field.
What Spring is doing in the first example is essentially that - it breaks encapsulation to change the value of a private value. (There is a way to overcome this with "opens" directive in module-info..)
You are also becoming dependent on the framework you are using and your code becomes harder to test compared to when using a simple setter.
You are also not explicitly declaring that your class depends on another class since I can easily instantiate it and "Other" will be null.
Some resources:
https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-scanning-autodetection (search for jigsaw)
https://blog.marcnuri.com/field-injection-is-not-recommended/
PS: You are probably missing #Configuration on your class
I want to write an integration test for a Spring Data repository and wonder what's the preferred way to make the repository available in the test class.
When testing my own plain old services, I use something like this to avoid having to use field injection, because field injection should not be used according to Spring Data project lead Oliver Gierke:
public class myServiceTest {
private MyService myService;
#Before
public void setUp() {
myService = new MyService();
}
[...]
}
But Spring Data repositories are defined as interfaces without an implementation because the Spring magic creates the implementation dynamically.
public interface FruitRepository extends CrudRepository<Fruit, Long> {
List<Fruit> findByName(String name);
}
Therefore there is no constructor I could use like this.
Using constructor injection, as in the follwoing example, also does not work, because it yields an Exception when trying to run the test:
#Autowired
public MyServiceTest(MyService myService) {
this.myService = myService;
}
java.lang.Exception: Test class should have exactly one public zero-argument constructor
As far as I can see, the only option I'm left with is injecting the repository via field injection as in the following working example:
#RunWith(SpringRunner.class)
#SpringBootTest
public class FruitRepositoryTest {
#Autowired
private FruitRepository fruitRepository;
#Test
public void findByNameFindsAnExistingFruit() {
fruitRepository.deleteAll();
fruitRepository.save(new Fruit("Orange"));
List<Fruit> foundFruits = fruitRepository.findByName("Orange");
assertFalse(foundFruits.isEmpty());
}
#Test
public void findByNameDoesNotFindANonExistingFruit() {
fruitRepository.deleteAll();
fruitRepository.save(new Fruit("Apple"));
List<Fruit> foundFruits = fruitRepository.findByName("Orange");
assertTrue(foundFruits.isEmpty());
}
}
So, my question is: Is this a legitimate exception to the rule to avoid field injection or am I missing something? Or am I maybe overthinking this, because field injection is okay to use in test classes anyway?
For tests, this is perfectly fine.
With the current version of JUnit there is really no reasonable way to do it differently.
The point of preferring constructor injection is that other pieces of code can instantiate the class properly without using any reflection magic. But nobody but JUnit will try to instantiate your tests, so the argument is void.
The integration tests of Spring Data itself use this approach. See for example here https://github.com/spring-projects/spring-data-jpa/blob/master/src/test/java/org/springframework/data/jpa/repository/UserRepositoryTests.java#L97 Note that Oliver is among the authors so I guess he approves as well.
I started to use constructor injection in my projects since Spring declared field injection to be deprecated. Actually, the code feels prettier and more strict, I'm ok with that.
But I encountered a pattern which seems a bit...weird and verbose to me:
I have an abstract service bean class (with #Service annotation), which has, say 2 dependencies, injected directly in the constructor:
#Autowired
public AbstractService(DependencyA depA, DependencyB depB) {
this.depA = depA;
this.depB = depB;
}
Then I have multiple services bean classes (still with #Serviceannotation) extending the abstract one.
And I don't know if there is another way but this is where I find a bit verbose and repetitive having to inject the dependencies for the parent, in each sub-class constructor:
#Service
public class ServiceA extends AbstractService {
private final DepC depC;
#Autowired
public ServiceA(DepA depA, DepB depB, DepC depC) {
super(depA, depB);
this.depC = depC;
}
}
I just wanted to know if this is the right way, and what you think about this ?
The #Autowired on AbstractService doesn't do anything. Change it to:
#Service
public class ServiceA extends AbstractService {
private final DepC depC;
#Autowired
public ServiceA(DepA depA, DepB depB, DepC depC) {
super(depA, depB);
this.depC = depC;
}
}
...
public AbstractService(DependencyA depA, DependencyB depB) {
this.depA = depA;
this.depB = depB;
}
I'm ok with this setup.
For me, the main benefits of using constructor injection is to inform the developer what are the external dependencies. I find it useful when writing unit test. When writing mocks, you just know what needs to be mocked.
An other benefit is to highlight when a Class has too many dependencies, it gives a hint that refactoring may be in order.
The alternative would be using setter injection (while keeping the informational aspect), but I've grown to enjoy constructor injection.
My answer is focusing about the "verbose and repetitive" part in your question; I let others decide how "correct" your usage of annotations is.
Even with Spring and its DI framework, in the end we are still talking about Java source code!
And in Java, if your base class only offers a constructor that takes some A and B; then of course your subclass has to make a call super(A a, B b); and of course, those values a and b have to come from somewhere!
So, what you call "verbose and repetitive" is a direct consequence of using Java.
In other words: there is no way to avoid that part!
Usually I define logger like this:
private static final Logger logger = LoggerFactory.getLogger(MyClass.class);
But when using #Inject we must use non-static and non-final field, like:
#Inject
private Logger logger;
i.e. logger will be created in each instance of this class, also logger is mutable. May be exist some way to make logger static? Also how I can bind logger to certain class (I use send the class object when creating logger object from factory LoggerFactory.getLogger(MyClass.class);, how to create logger in same way using injecting ? )?
Please check the Custom Injections on Guice wiki, there is a complete Log4J example.
EDIT: You can use either a static field or a final field for your logger, but not a static final one. This is a Java limitation.
Also be wary that:
Injecting final fields is not recommended because the injected value may not be visible to other threads.
Haven't tested that but the code in the article should work fine for static fields, although you could improve it by getting rid of MembersInjector and doing all of it in the TypeListener (since a static field needs to be set only once).
Using requestStaticInjection() will force you to list all your classes in a module file - not a good idea, as you will soon forget to add one.
OTOH if you just want to support JUL you might be better of using the built-in support (as mentioned by Jeff, I assumed you didn't want a general answer, since you didn't mention JUL specifically in your question).
When designing your application for dependency injection, typically the best practice is to avoid static fields and methods as much as possible. This is so that your dependencies are clearer, and so it's easier to replace your real dependencies with other instances during tests and as your application evolves. The ideal behavior, therefore, is to avoid static methods and fields (including loggers) as much as possible.
Guice, however, does allow for marking fields static, and requesting injection of static fields when the Injector is created. The fields will need to remain mutable--final doesn't mean "final except for Guice".
public class YourClass {
#Inject static Logger logger;
/* ... */
}
public class YourModule extends AbstractModule {
#Override public void configure() {
/* YourClass.logger will work once you create your Injector. */
requestStaticInjection(YourClass.class);
}
}
Guice automatically provides java.util.logger.Logger instances for you with the class name embedded into it, but that's only because of a special case coded into Guice. If you want a special logger, as in this SO question, you'll need to investigate the Custom Injections to which Jakub linked--but if the whole goal is to centralize logger creation so you can control it in one place, you can just refactor that into a static factory outside of Guice too.
#LogToFile
public class YourClass {
private static final Logger logger = YourLoggerFactory.create(YourClass.class);
/* ... */
}
public class YourLoggerFactory {
private YourLoggerFactory { /* do not instantiate */ }
public Logger create(Class<?> clazz) {
if (clazz.getAnnotation(LogToFile.class) != null) {
return someImplementation(new File(...));
} else {
return someOtherImplementation();
}
}
}
I see many Java examples using dependency injection with private fields without a public setter like this:
public SomeClass {
#Inject
private SomeResource resource;
}
But that is a bad idea when the injection should be performed manually for example in unit tests.
There are several possibilities to solve this:
add a public setter: setSomeResource(SomeResource r)
make the field public
make the field package protected
I'd like to avoid the setter, since nothing really happens in it. So I'd prefer public or package protected. What do you recommend?
One way to avoid creating a setter for the field is using constructor injection. This even allows you to declare the field as final.
It goes like this:
public class SomeClass {
private final SomeResource resource;
#Inject
public SomeClass(SomeResource resource) {
this.resource = resource;
}
}
Adding setters is not an optimal solution, since you are adding production code which is not needed.
An alternative is to use Spring's ReflectionTestUtils class to inject your test dependencies using reflection, see http://static.springsource.org/spring/docs/2.5.x/api/org/springframework/test/util/ReflectionTestUtils.html
EDIT (2017): However, reflection is an even worse solution than adding setters. The cause of this mess is the fact that Spring makes it possible to inject values without setters or constructors. My current stance is to stick to using either of those and avoid using black magic injection practices.
I prefer the setter
it is easier to debug (put a breakpoint in a setter rather than on field access / modification)
easier to log
easier to add some validation (although this is not always the best place)
easier to support bidirectional maintainance (though IOC container can take care of that)
any other "manual AOP" purpose
But that's just my opinion
I recommend using setter. In this question are the benefits of using getters and setters.
With the help of the answer to my (related to this one) question:
How do app servers inject into private fields?
I coded this simple example on how to inject without setters.
Perhaps it helps
//......................................................
import java.lang.annotation.*;
import java.lang.reflect.*;
//......................................................
#Target(value = {ElementType.FIELD})
#Retention(RetentionPolicy.RUNTIME)
#interface Inject {
}
//......................................................
class MyClass {
#Inject
private int theValue = 0;
public int getTheValue() {
return theValue;
}
} // class
//......................................................
public class Example {
//......................................................
private static void doTheInjection(MyClass u, int value) throws IllegalAccessException {
Field[] camps = u.getClass().getDeclaredFields();
System.out.println("------- fields : --------");
for (Field f : camps) {
System.out.println(" -> " + f.toString());
Annotation an = f.getAnnotation(Inject.class);
if (an != null) {
System.out.println(" found annotation: " + an.toString());
System.out.println(" injecting !");
f.setAccessible(true);
f.set(u, value);
f.setAccessible(false);
}
}
} // ()
//......................................................
public static void main(String[] args) throws Exception {
MyClass u = new MyClass();
doTheInjection(u, 23);
System.out.println(u.getTheValue());
} // main ()
} // class
Run output:
------- fields : --------
-> private int MyClass.theValue
found annotation: #Inject()
injecting !
23
With field based injection, you run into the issue you describe with testing. Also with setter based injection, an instance of a class can be created in an incomplete state when running tests if you forget to set some of the dependencies. I have been practicing constructor injection most recently due to the fact that it forces you to set all dependencies whenever you create an instance of a class during testing. The answer above by Andre Rodrigues explains how this would be accomplished.
Possible solutions to this:
Use a CDI-aware testing framework like JGlue CDI-Unit. This way you need no setter. You only define the dependency inside your tests - usually using a Mockito mock object. IMHO this is the best solution, since it doesn't require you to do anything extra for testing.
Inject into Constructor or setter. That's right, you can inject into setters! More details here.
Use a protected setter. Simple and works in every case. Since it's protected, you can access it from your test class (which should have the same package definition as your tested class), and no other packages can access it.
Use a getter and override it when testing. In your test class, create a new inner class that extends the tested class and override the getter. This, however, has a big disadvantage: your test class has to use the getter internally instead of the field. Lots of potentially bugged boilerplate...