How does Autowire work when referring only to a base class - java

I am trying to extend existing code which auto-wires a number of components which share the same base class and are only referred to by their base class, ei:
#Configuration
public class NavigationHotKeyBindConfigs {
private static final Logger logger = LogManager.getLogger(NavigationHotKeyBindConfigs.class);
#Autowired
private HotKeyConfig hotKeyConfig;
#Autowired
private ANavigation upNavigation;
#Autowired
private ANavigation downNavigation;
#Autowired
private ANavigation centerOnSelection;
#Autowired
private ANavigation handVerify;
public abstract class ANavigation {
#Autowired
protected ScrollSchedulerConfigurer scrollSchedulerConfigurer;
public abstract void execute(DetectionView DetectionView);
}
#Component
public class DownNavigation extends ANavigation{
private static final Logger logger = LogManager.getLogger(DownNavigation.class);
public void execute(DetectionView detectionView){
logger.info(String.format("Received: Navigation key %s", ENavigationKey.DOWN.name()));
scrollSchedulerConfigurer.stop();
detectionView.selectNextDetection();
}
}
#Component
public class UpNavigation extends ANavigation{
private static final Logger logger = LogManager.getLogger(UpNavigation.class);
public void execute(DetectionView detectionView){
logger.info(String.format("Received: Navigation key %s", ENavigationKey.Up.name()));
scrollSchedulerConfigurer.stop();
detectionView.selectPrevDetection();
}
}
I don't understand how spring is ever supposed to match up upNavigation/downNavigation with the UpNavigation/DownNavigation components respectively. Was this just bad design from the original author or is there a subtlety I'm missing?
This lack of understanding is also causing some issues as the centerOnSelection and handVerify objects end up NULL after autowiring though they follow the same pattern in every way I can see. Interestingly, this last behavior is different when run in the intellij IDE vs when run out of a .jar

You can do it like this ...
Let's say we have two beans which have the same base class or interface
#Component("fooFormatter")
public class FooFormatter implements Formatter {
public String format() {
return "foo";
}
}
#Component("barFormatter")
public class BarFormatter implements Formatter {
public String format() {
return "bar";
}
}
Then we inject them like this ...
public class FooService {
#Autowired
#Qualifier("fooFormatter")
private Formatter formatter;
}
From the point of view of clarity and maintainability this seems to be the best solution

#Autowired first looks at the type of the variable and then the name of the variable to match the correct bean. By default, the name of a class marked with #Component is its short name, e.g. upNavigation for the UpNavigation class.
#Autowired
private ANavigation upNavigation;
is the same as
#Autowired
#Qualifier("upNavigation")
private ANavigation upNavigation;
And
#Component
public class UpNavigation
is the same as
#Component("upNavigation")
public class UpNavigation
Since the names match, Spring is able to find the corresponding bean.

Related

How to perform an #Entity query inside a ConstraintValidator

The scenario is that before persisting a Log entity class, its property, String description should be checked if it contains at least a word found in the IllegalWord entity class. Here is the mapping of the two entity classes:
// Log.java
#Entity
public class Log {
#GeneratedValue(strategy=GenerationType.SEQUENCE)
#Id
private Long id;
#NotContainingIllegalWords
private String description;
}
// IllegalWord.java
#Entity
public class IllegalWord {
#GeneratedValue(strategy=GenerationType.SEQUENCE)
#Id
private Long id;
private String word;
}
Since I will be performing a select * to the IllegalWord entity class, I created a repository class for it:
// IllegalWordRepository.java
#Repository
public interface IllegalWordRepository extends CrudRepository<IllegalWord, Long> {}
And then created the ConstraintValidator validator class that will be used by NotContainingIllegalWords annotation, that in turn, will be use to annotate the String description field of Log entity class:
// NotContainingIllegalWordsValidator.java
public class NotContainingIllegalWordsValidator implements ConstraintValidator<NotContainingIllegalWords, Object> {
private static final Logger log = LoggerFactory.getLogger(NotContainingIllegalWordsValidator.class);
#Autowired
private IllegalWordRepository illegalWordRepository;
public void initialize(NotContainingIllegalWords constraintAnnotation) {}
public boolean isValid(String value, ConstraintValidatorContext cxt) {
log.debug("illegalWordRepository is null? " + (illegalWordRepository == null));
// Returns "illegalWordRepository is null? true"
// It is not injected even with the #Autowired annotation.
boolean valid = true;
Collection<IllegalWord> illegalWords = illegalWordRepository.findAll();
// Encounters a NullPointerException here.
// valid = ...loop through illegalWords collection and match regex (or whatever optimal approach)
// with #param value to check if it contains the illegal word.
return valid;
}
I thought it will be as straight-forward like that. But the statement illegalWordRepository.findAll() throws an error because the illegalWordRepository variable is null. Notice that I tried to check if it is null in the preceding statement.
I assumed that I have something wrong coded within the repository class so I attempted to used #Autowired private IllegalWordRepository illegalWordRepository inside a #Service annotated class and suprisingly it is injected there properly (e.i. not null):
// IllegalWordService.java
#Service
public class IllegalWordService {
private static final Logger log = LoggerFactory.getLogger(IllegalWordService.class);
#Autowired
private IllegalWordRepository illegalWordRepository;
public IllegalWord generate(String word) {
log.debug("illegalWordRepository is null? " + (illegalWordRepository == null));
// Returns "illegalWordRepository is null? false"
IllegalWord illegalWord = new IllegalWord();
illegalWord.setWord(word);
illegalWordRepository.save(illegalWord);
// Didn't encounter a NullPointerException here.
return illegalWord;
}
}
Therefore, I guess nothing is wrong with the IllegalWordRepository repository class. It's just that it is not injected in NotContainingIllegalWordsValidator validator class as I intended it to be with the #Autowired annotation (if that is how #Autowired annotation was intended to function even, I am sorry I am new in Spring Framework.).
If there is a proper approach on how to perform a #Entity query inside a ConstraintValidator instance, please tell me.
Related unanswered SO question: Inject Repository inside ConstraintValidator with Spring 4 and message interpolation configuration
Failed Attempt:
I tried to annotate the NotContainingIllegalWordsValidator class with #Configurable annotation, like so:
#Configurable(autowire=Autowire.BY_NAME, preConstruction=true)
public class NotContainingIllegalWordsValidator implements ConstraintValidator<NotContainingIllegalWords, Object> {
but the illegalWordRepository property remains null.
Since Your validator is not initialized by Spring, you can't inject anything into it. You'd have to access the ApplicationContext through a static variable.
#SpringBootApplication
public class MyApplication {
private static ApplicationContext applicationContext;
public static void main(final String[] args) {
applicationContext = SpringApplication.run(MyApplication.class, args);
}
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
}
And in your ConstraintValidator:
public class NotContainingIllegalWordsValidator implements ConstraintValidator<NotContainingIllegalWords, Object> {
public boolean isValid(String value, ConstraintValidatorContext cxt) {
ApplicationContext applicationContext = MyApplication.getApplicationContext();
IllegalWordRepository illegalWordRepository = applicationContext.getBean(IllegalWordRepository.class);
...
}
}
From my answer to a similar question:
The minimum setup for #Autowired to work properly in ConstraintValidator implementation is to have this bean in a Spring #Configuration:
#Bean
public Validator defaultValidator() {
return new LocalValidatorFactoryBean();
}
This is the demo project

Does a Java interface work different in Spring Boot? -- Is this Spring Wizardry or do I just not understand interfaces?

I'm working on an application that uses Spring Boot. In it, an interface is used in a way that I don't understand.
I've stripped down the code to the only parts that I think are relevant to the question.
A controller object is created.
It is told to process some stuff.
The controller tells an interface processor to do the work.
There is a processor that implements the interface processor.
It was my understanding that when using an interface you'd do something like: IProcessor iProcessor = new Processor();
In other words, assigning the interface an implementation. But in this sample program it seems the processor implementation is implicitly assigned, not in the code as far as I can tell. I'm trying to figure out if this is some Spring wizardry or if I'm just understanding interfaces wrong. There are four files that I have put in order of application flow.
#Component
public class DoStuff {
private ProcessorController PROCESSOR_CONTROLLER;
private OtherLayer OTHER_LAYER;
#Autowired
public DoStuff(ProcessorController processorController, OtherLayer otherLayer) {
this.PROCESSOR_CONTROLLER = processorController;
this.OTHER_LAYER = otherLayer;
}
public void execute() {
List<String> stuffToProcess = OTHER_LAYER.getStuffToProcess();
PsROCESSOR_CONTROLLER.process(stuffToProcess);
}
}
#Component
public class ProcessorController {
private final IProcessor IPROCESSOR;
#Autowired
public ProcessorController(IProcessor iProcessor) {
this.IPROCESSOR = iProcessor;
}
public void process(List<String> stuffToProcess) {
stuffToProcess.forEach(t -> IPROCESSOR.process(t))
}
}
public interface IProcessor {
void process(String stuff);
}
#Component
public class Processor implements IProcessor {
#Override
public void process(String stuff) {
System.out.println(stuff);
}
}
If the ProcessorController class contained something like this:
So part of the ProcessorController class would look like this instead:
private final IProcessor IPROCESSOR;
#Autowired
public ProcessorController(Processor Processor) {
this.IPROCESSOR = processor;
}
I think it would make sense since we've linked the interface with its implementation. But it isn't that way. So what is going on here?
Your understanding is correct
IProcessor iProcessor = new Processor();
The above way is correct way to assigning the implementation to Interface reference variable.This phenomena is known as loose coupling .Because if the method parameter type is of interface then it can be bind with multiple implementation based on requirement .
For Example we have
interface Test and Test1 and Test2 are its implementation classes
Then void method(Test test)
so now this method can bind with both Test1 and Test2 like method(Test1 obj) and method(Test2 obj)
But your controller is tightly coupled here not loosely coupled.Because Your constructor call is bind with Implementation class reference not interface.And if your project need tight coupling then there is no use to create class refrence of interface type rather you can create private final Processor PROCESSOR; instead of below code
private final IProcessor IPROCESSOR;
#Autowired
public ProcessorController(Processor Processor) {
this.IPROCESSOR = processor;
}
It should be like
#Autowired
private final IProcessor IPROCESSOR;
or
private final IProcessor IPROCESSOR;
#Autowired
public ProcessorController(IProcessor Processor) {
this.IPROCESSOR = processor;
}

BeanCreationException error when referencing configuration class inside a service class

I am trying to #Autowire a #Configuration class inside a #Service class. basically my #Configuration class contains mapping to my custom .properties file. When i try to autowire my configuration class inside my service class, BeanCreationException occurs. I am not sure what happen. Just followed the guide on creating Property classes from spring. There must be something i missed out.
Also, when i try to autowire #Configuration class to another #Configuration class, it runs smoothly
Currently, i know that, prop is always null because when i remove prop.getUploadFileLocation() call, everything will be fine. There must be something wrong during autowiring.
Here is my Service class
#Service
public class ImageService {
public static Logger logger = Logger.getLogger(ImageService.class.getName());
#Autowired
MyProperties prop;
private final String FILE_UPLOAD_LOCATION = prop.getUploadFileLocation() +"uploads/images/";
public void upload(String base64ImageFIle) throws IOException {
logger.info(FILE_UPLOAD_LOCATION);
}
}
Here is my Configuration class
#Data
#Configuration
#ConfigurationProperties (prefix = "my")
public class MyProperties {
private String resourceLocation;
private String resourceUrl;
public String getUploadFileLocation() {
return getResourceLocation().replace("file:///", "");
}
public String getBaseResourceUrl() {
return getResourceUrl().replace("**", "");
}
}
And here is where i can successfully use MyProperties
#Configuration
public class StaticResourceConfiguration implements WebMvcConfigurer {
#Autowired
MyProperties prop;
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler(prop.getResourceUrl())
.addResourceLocations(prop.getResourceLocation());
}
}
The issue is that you are trying to use an autowired field to set the value in an inline field assignment.
That means
private final String FILE_UPLOAD_LOCATION = prop.getUploadFileLocation() +"uploads/images/";
is executed before the prop is autowired, meaning it will always be null
The way to mitigate this would be to use constructor injection instead.
#Service
public class ImageService {
//Fine since you are using static method
public static Logger logger = Logger.getLogger(ImageService.class.getName());
//Not needed if you are only using it to set FILE_UPLOAD_LOCATION
//Allows field to be final
private final MyProperties prop;
//Still final
private final String FILE_UPLOAD_LOCATION;
//No need for #Autowired since implicit on component constructors
ImageService(MyProperties prop){
//Again not needed if you aren't going to use anywhere else in the class
this.prop = prop;
FILE_UPLOAD_LOCATION = prop.getUploadFileLocation() +"uploads/images/";
}
public void upload(String base64ImageFIle) throws IOException {
logger.info(FILE_UPLOAD_LOCATION);
}
}
See this question for why constructor is preferred over #autowired in general
If you need MyProperties bean to be created before StaticResourceConfiguration bean, you can put #ConditionalOnBean(MyProperties.class) as following. Spring will make sure MyProperties is there before processing StaticResourceConfiguration.
#Configuration
#ConditionalOnBean(MyProperties.class)
public class StaticResourceConfiguration implements WebMvcConfigurer {

Parameter 3 of constructor in required a bean of type 'package' that could not be found

I have call method which is defined in NoteService interface, the implementation of this method is in NoteImpl class. I am trying to access this method from Refresh class, but I am getting this error
Parameter 3 of constructor in com.new.macro.rest.Refresh required a bean of type 'com.new.macro.unity.processorService' that could not be found.
Action:Consider defining a bean of type 'com.new.macro.unity.NoteService' in your configuration.
I need help resolving this error.
Here is my Refresh class from where I try to access call method from NoteImpl class
package com.new.macro.rest;
#Component
public class Refresh implements BaseService {
private final NoteService<Inbuild> iNoteService;
public Refresh(final NoteService iNoteService) {
this.iNoteService = iNoteService;
}
#PUT
public String firstRefresh() {
iNoteService.call(Types);
return RefreshStatus.STARTED.toJsonResponse();
}
Here is NoteImpl class with call method functionality
#Configuration
public abstract class NoteImpl implements NoteService{
private static final Logger LOGGER = LogManager.getLogger(NoteImpl.class);
private final RestTemplate restTemplate;
private final String Url;
public NoteImpl( RestTemplate restTemplate,#Value("${url}") String Url){
this.restTemplate = restTemplate;
this.Url = Url;
}
public void call(Set<Inbuild> Types, String Url) {
Set<String> results = new HashSet<>();
\\ Remaining functionality
}
}
Here is the interface
package com.new.macro.unity;
import java.util.Set;
public interface NoteService<T> {
void call(Set<? extends T> Types);
}
Add #Autowired annotation on head of constructor:
#Autowired
public Refresh(final NoteService iNoteService) {
this.iNoteService = iNoteService;
}
Then you will get a bean from NoteService.
Assuming all these classes are classpath scanned:
- NoteImpl shouldn't be abstract
- NoteImpl should be annotated as #Component instead of #Configuration. Configuration classes are the ones that create beans
To fix this, don't keep NoteImpl as abstract class - abstract classes can't be instantiated. That should resolve the problem. Though #Configuration will work(as it's meta annotated with #Component), #Service makes sense here.
Also, you don't need #Autowired at constructor injection - that is optional. (So the other answer won't solve the problem)

How to inject a Logger in an enum

When I try to inject my Logger producer in an enum, I get a NPE. How can I inject a Logger in an enum?
Example:
public enum MyEnum {
HI("Hi there!"),
HELLO("Hello mister!");
#Inject
private Logger log;
private final String greeting;
private MyEnum(String greeting) {
this.greeting = greeting;
// this.log = LoggerFactory.getLogger(this.getClass());
}
public String getGreeting() {
log.debug("Method getGreeting called");
return this.greeting;
}
}
This class gives me a NPE on the log.debug() line. When I remove the #Inject and uncomment the this.log line it works.
Testcase looks like this:
#RunWith(Arquillian.class)
public class CoverKindTest {
#Deployment
public static WebArchive createDeployment() {
return ShrinkWrap.create(WebArchive.class, "test.war")
.addClass(MyEnum.class)
.addClass(LoggerProducer.class)
.addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml");
}
#Test
public void testEnum() {
MyEnum myEnum = MyEnum.HI;
String greeting = myEnum.getGreeting();
assertThat("Should give the greeting.", greeting, is("Hi there!"));
}
}
Complete testable project for this question can be found here, MyEnum.class is the original question, MyEnum1.class is the solution without injection (working, but not what I am looking for) and MyEnum2.class is a suggested answer.
Edit: Updated the GitHub repo with a working solution.
https://github.com/martijnburger/how-to-inject-a-logger-in-an-enum
This direct injection won't work since enum is static.
You can either create a new logger in your enum class
private static final Logger log = Logger.getLogger(Myenum.class.getName());
Found a solution that works!
I created a helper class as follows:
public class LoggerHelper {
private static Logger logger;
private void injectLogger(#Observes #Initialized(ApplicationScoped.class) Object context,
Logger logger) {
LoggerHelper.logger = logger;
}
public static Logger getLogger() {
return logger;
}
}
Now I can inject the logger in the Enum using:
private final Logger log = LoggerHelper.getLogger();
Enums cannot be injected, as they're static.
If you still want injection (instead of just creating the Logger), then you need to create a static class inside your enum that has either setter or constructor injection. When the setter or constructor gets called by the DI framework, take the value it gives you and assign it yourself to a static value in the enum.
The enum can access it now as needed. Beware though, the value will be null if your class was not injected yet.
Something like this:
public enum MyEnum {
HI("Hi there!"),
HELLO("Hello mister!");
private static Logger log;
private final String greeting;
private MyEnum(String greeting) {
this.greeting = greeting;
}
public String getGreeting() {
log.debug("Method getGreeting called");
return this.greeting;
}
#Component
public static class InjectionHelper {
#Inject
public InjectionHelper(Logger log) {
MyEnum.log = log;
}
}
}
You can create a Singleton Service class (created by your respective DI Framework - say Spring), Inject this log inside that class and use it in your enum.
Here is a sample code which works. (Replace the Service annotation with a bean tag for this class in XML, if you're using XML way of doing it. Also you can neglect the lombok #Getter annotation and replace it with a static getter)
// Service which is actually a Utility class but have DI Managed Beans.
#Service("staticService")
public class StaticService {
#Getter
private static Logger log;
#Inject
StaticService(Logger log) {
StaticService.log = log;
}
}
Now in your corresponding Enum:
public String getGreeting() {
StaticService.getLog().debug("Method getGreeting called");
return this.greeting;
}
I used a similar pattern for one of my classes (In Spring) and the injection worked.
Logic:
We first create an instance of the class (singleton instance) and inject the needed variable in the constructor.
Since this gets called during spring initialization (During Application startup), the log is initialized and we manually assign the static variable of log with the injected object in the constructor.
Note:
Don't forget the Inject annotation in the constructor Args.
Better to not provide a setter method to this log object. As its static and shared, we don't want people to replace this value post-construction. (Making it final is not an option as its static).

Categories