I have a logger class that makes use of a service. Each time a new logger is created, I expect to have access to the singleton scoped logging service.
I autowire the logging service into the logger however, a null pointer exception is returned. I have tried a few solutions:
manually defining the bean in the application context,
Trying to get the logger to be spring managed but that just resulted in more issues.
I am trying to get this to work in my junit tests, and I do specify the context file to make use of a different application context. However even if kept identical it does not resolve the issue.
Please find code below:
The following is an excerpt from the application context.
<context:component-scan base-package="com.platform"/>
<bean id="asyncLoggingService" class="com.platform.services.AsyncLoggingServiceImplementation" scope="prototype"/>
The following is the Logger class.
package com.platform.utils;
import com.platform.services.AsyncLoggingService;
import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
public class OurLogger
{
private static Logger logger;
#Autowired
private AsyncLoggingervice asyncLoggingService;
public OurLogger(Class Clazz)
{
logger = LoggerFactory.getLogger(Clazz);
}
public void trace(TraceableObject object, String message)
{
//Do nothing yet
}
}
I then make use of the Logger in another service in order to log whats going on. (The reason I am writing another logger is to make use of an RabbitMQ server) In the service I instantiate a new instance of the Logger and then use it accordingly.
#Service
public class AsyncAccountServiceImplementation implements AsyncAccountService
{
private static final String GATEWAY_IP_BLOCK = "1";
private static OurLogger logger = new OurLogger(AsyncAccountServiceImplementation.class);
...
}
The null pointer occurs in the OurLogger when I try to call any method on the asyncLoggingService.
I then am trying to test the AsyncAccountService using JUnit. I make sure I add the different application context but it still seems to result in the null pointer exception.
If you need further information please let me know. I have seen ways to fix this but they don't seem to work so perhaps I have made a mistake somewhere or I am not understanding this all quite correctly.
When you create an object by new, autowire\inject don't work...
See this link and this link for some workaround.
Anyway if you would inject a logger i suggest you this my answer to another topic.
Just want to add my 2 cents.
I once encountered the same issue when I was not quite used to the life in the IoC world. The #Autowired field of one of my beans is null at runtime.
The root cause is, instead of using the auto-created bean maintained by the Spring IoC container (whose #Autowired field is indeed properly injected), I am newing my own instance of that bean and using it. Of course this one's #Autowired field is null because Spring has no chance to inject it.
If you are using AspectJ you can use #Configurable:
#Configurable
public class OurLogger {
..
}
See: Using AspectJ to dependency inject domain objects with Spring
Use spring framework Unit test instead of JUnit test to inject your spring bean.
May be that will help you.
Within your application context you have to do reference your Logger :
<context:component-scan base-package="com.platform"/>
<bean id="asyncLoggingService" class="com.platform.services.AsyncLoggingServiceImplementation" scope="prototype"/>
<bean id="ourLogger" class="com.platform.utils.OurLogger"/>
Then you've to inject it into your service :
#Service
public class AsyncAccountServiceImplementation implements AsyncAccountService
{
private static final String GATEWAY_IP_BLOCK = "1";
#Autowired
private OurLogger logger;
}
Related
In a real project, I found out that #Component may be omitted in the following code:
// no #Component !!!!!
public class MovieRecommender {
private final CustomerPreference customerPreference;
#Autowired
public MovieRecommender(CustomerPreference customerPreference) {
this.customerPreference = customerPreference;
}
// ...
}
#Component
public class CustomerPreference {...}
(The example is taken from the official Spring docs https://docs.spring.io/spring-framework/docs/4.3.x/spring-framework-reference/htmlsingle/#beans-autowired-annotation , and the docs show no #Component at all, which may mean either that it is not needed, or that it is just not shown.)
The project where I work does not use any XML bean declarations, but it uses frameworks other than just Spring, so it is possible that something declares the class as a bean. Or it may be a feature of the version of Spring that we use, and if that feature is not documented, it may be dropped later.
Question:
Must the class that uses #Autowired be annotated with #Component (well, be a bean)? Is there any official documentation about that?
UPD Folks, there is no #Configuration and no XML configs in the project, I know that such declarations make a bean from a class, but the question is not about them. I even wrote "(well, be a bean)" in the question above to cover that. Does #Autowired work in a class that is not a bean? Or maybe it declares the class that uses it as a bean?
there are several ways to instantiate a bean in Spring.
One of them indeed is with the #Component annotations, with that, Spring will scan all the packages defined for component-scan and initialize all annotated classes (either with #Component or one of the annotations that uses it - Controller, Service, etc.).
Other way to initialise beans is using a configuration class (annotated with #Configuration) that includes methods annotated with #Bean. each of these methods will create a bean.
There's also an option to create the beans using xml configurations, but this is becoming less and less common, as the annotation-based approach is more convinient
According to https://stackoverflow.com/a/3813725/755804 , with autowireBean() it is possible to autowire a bean from a class not declared as a bean.
#Autowired
private AutowireCapableBeanFactory beanFactory;
public void sayHello(){
System.out.println("Hello World");
Bar bar = new Bar();
beanFactory.autowireBean(bar);
bar.sayHello();
}
and
package com.example.demo;
import org.springframework.beans.factory.annotation.Autowired;
public class Bar {
#Autowired
private Foo foo;
public void sayHello(){
System.out.println("Bar: Hello World! foo="+foo);
}
}
On the other hand, by default the latest Spring does not assume that classes that use #Autowire are #Component-s.
UPD
As to the mentioned real project, the stack trace shows that the constructor is called from createBean(). That is, the framework creates beans from classes declared in the framework's configs.
I am very new to Micronauts and I have a fair bit of experience developing spring boot applications. With this background I was stumbled upon creating custom beans like how I used to create with #Bean annotations on Spring applications.
In my case I have a library that provides an Interface and its implementation class. I wanted to use the interface in my code and try to inject the implementation and it failes with below error
Caused by: io.micronaut.context.exceptions.NoSuchBeanException: No bean of type [io.vpv.saml.metadata.service.MetaDataParser] exists for the given qualifier: #Named('MetaDataParserImpl'). Make sure the bean is not disabled by bean requirements (enable trace logging for 'io.micronaut.context.condition' to check) and if the bean is enabled then ensure the class is declared a bean and annotation processing is enabled (for Java and Kotlin the 'micronaut-inject-java' dependency should be configured as an annotation processor).
Here is my code
#Singleton
public class ParseMetadataImpl implements ParseMetadata {
private Logger logger = LoggerFactory.getLogger(this.getClass());
#Inject
#Named("MetaDataParserImpl")
private MetaDataParser metaDataParser;
#Override
public IDPMetaData getIDPMetaData(URL url) throws IOException {
logger.info("Parsing {}", url);
logger.info("metaDataParser {}", metaDataParser);
return metaDataParser.parseIDPMetaData(url);
}
}
I am sure there is somehting wrong I am doing and need to understand what to do. I have this working by adding below code and removing annotations around metaDataParser.
#PostConstruct
public void initialize() {
//Want to Avoid This stuff
this.metaDataParser = new MetaDataParserImpl();
}
Using Spring Boot it would be possible to add a #Bean annotation to create some custom beans we can do #Autowired to inject it everywhere on our application. Is there an equivalent on Micronauths that I am missing. I went through the guide on https://docs.micronaut.io/2.0.0.M3/guide/index.html and was not able to get anything to get this working.
Can someone suggest how I can use the #Inject to inject custom beans?
Just incase you want to see this, here is the application on Github.
https://github.com/reflexdemon/saml-metadata-viewer
With the help from Deadpool and a bit of reading I got what I was looking for. The solution was creating #BeanFactory
See Javadoc here: https://docs.micronaut.io/latest/guide/ioc.html#builtInScopes
The #Prototype annotation is a synonym for #Bean because the default scope is prototype.
Thus here is an example that will match the the behavior of Spring framework
Here is the answer for anyone who also is looking for such a thing.
import io.micronaut.context.annotation.Factory;
import io.vpv.saml.metadata.service.MetaDataParser;
import io.vpv.saml.metadata.service.MetaDataParserImpl;
import javax.inject.Singleton;
#Factory
public class BeanFactory {
#Singleton
public MetaDataParser getMetaDataParser() {
return new MetaDataParserImpl();
}
}
I got a project with tons of services and repositories. Currently each repository is autowired to a service using annotations.
#Service
public class Service1 {
#Autowired
private Repository1 repository1;
#Autowired
private Repository2 repository2;
...100+ more
}
All of these repository are under the same package. Is it possible to skip declaration for each repository?
A simple solution I found would be to implement an interface like this:
#Autowired
private Map<String,RepositoryInterface> repositoryInterface
public void method1(){
repositoryInterface.get("repository1").doMethod();
}
It should have been a good solution but problem is I don't have access to all the source codes. I have tons of repository classes that I am not allowed to change to add an interface class.
So is there another way to solve this? Like just scan the whole package and just use bean name to access the repositories?
Beans are retrievable from their class or their name (and both).
In your case, you could rely directly on their class to retrieve them from the context.
Inject an ApplicationContext (or constructor way) :
#Autowired
private ApplicationContext applicationContext;
And use it :
applicationContext.getBean(RepositoryOne.class).doMethod1();
Ideally it should be extracted into a method :
public <T> T getRepository(Class<T> clazz){
return applicationContext.getBean(clazz);
}
to be used more simply :
getRepository(RepositoryOne.class).doMethod(1);
But I would warn about needing so many field dependencies in a class.
This makes it very hard to maintain/to test and also very error prone to use.
The best thing to do is rethink your design to avoid such complex/bloat class.
Besides using structure like private Map<String,RepositoryInterface> repositoryInterface or ApplicationContext will make you lose the benefit from dependency checks performed by the Spring container at startup that prevents NullPointerException and errors related to inconsistency (dependency missing) during the application working.
I'm creating a REST web application with Java, Tomcat and Jersey. I'm using annotations (no web.xml!) I ended up using this application configuration:
package com.my_own.server;
import java.util.Properties;
import javax.ws.rs.ApplicationPath;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import com.my_own.db.PostgreSQLDb;
#ApplicationPath("/api")
public class Application extends javax.ws.rs.core.Application {
private static Logger logger = LogManager.getLogger(Application.class);
public static Application application = null;
public final Properties properties;
public final PostgreSQLDb adminDb;
public Application() throws Exception {
logger.debug("Loading properties from ",
getClass().getClassLoader().getResource("config.properties"));
properties = new Properties();
properties.load(getClass().getClassLoader().getResourceAsStream("config.properties"));
adminDb = new PostgreSQLDb(properties, "admin");
application = this; // Setting the global application object here
}
}
Here is my problem. There is a single global application objects for the web container. I'm saving it into a static field, from the application constructor. I need to access it from other classes later (it holds the global configuration, a global database connection factory, and probably other things.)
Am I doing this right? I suspect that there must be a better way: save a reference to the application when annotations are processed. But I'm not sure how. Can I be sure that the Application's constructor will be called exactly once, and the Application.application reference can be accessed later, from any REST call?
Use dependency injection in jersey, bind your application when initializing:
public class MyApplication extends ResourceConfig {
public MyApplication() {
super(MyApplication.class);
register(new MyBinder());
packages(true, "location.of.my.jersey.classes");
}
/* Bind is used to let jersey know what can be injected */
private static class MyBinder extends AbstractBinder {
#Override
protected void configure() {
bind(MyApplication.class).to(MyApplication.class);
}
}
}
Then in your code:
#Path("myapi")
#Produces(MediaType.APPLICATION_JSON)
public class ServerRoutes {
#Inject
MyApplication application;
//... your rest code here
}
Now you can access MyApplication from within your code without needing any statics or singletons, jersey handles it.
Let me share my opinion: you can use of course a well-known Singleton pattern to store a "global" static object, however, it's really an antipattern these days.
If it's not a homework or something then storing global "static" objects is always a bad idea design-wise. If you want to know why there are many sources that answer this question, like this discussion for example
So I suggest considering using a Dependency Injection container instead, There are many really good containers out there: Spring, Guice to name a few.
These containers can store these objects as beans and if your "pieces" of functionality are also managed by these containers, you'll be able to "inject" application beans right into the controller.
It effectively solves all the issues introduced by singleton pattern.
Is it possible to use #Configurable on a class that's weaved using AspectJ and get Spring to load in values on fields/methods which are annotated with #Value?
I know its possible with #Autowired and #Resource etc... Are there any others.
e.g.
#Configurable
public Class MyObj{
#Value("$(my.prop)")
private String aField;
public String getAField(){
return aField;
}
}
And then have something like
public aMethodSomewhereElse(){
MyObj obj = new MyObj()
assertNotNull(obj.getAField());
}
Are there any alternatives to being able to create MyObj with the new operator and still get spring to handle the annotations?
--EDIT:--
It IS possible to do this using new when using #Autowired, have a look at some Hibernate and JPA stuff with Spring and AOP... I've used this in the past to do some profiling of Java code. But I really want to use SPEL and #Value before I mock up a full example I was hoping to find the answer here. FYI - if you don't belive me the Spring Manual even says it is possible to do this, what I want to know is if its possible to use #Value annotations in the same scope...
The Spring container instantiates and configures beans defined in your
application context. It is also possible to ask a bean factory to
configure a pre-existing object given the name of a bean definition
containing the configuration to be applied. The spring-aspects.jar
contains an annotation-driven aspect that exploits this capability to
allow dependency injection of any object.
And...
Using the annotation on its own does nothing of course. It is the
AnnotationBeanConfigurerAspect in spring-aspects.jar that acts on the
presence of the annotation. In essence the aspect says "after
returning from the initialization of a new object of a type annotated
with #Configurable, configure the newly created object using Spring in
accordance with the properties of the annotation". In this context,
initialization refers to newly instantiated objects (e.g., objects
instantiated with the 'new' operator) as well as to Serializable
objects that are undergoing deserialization (e.g., via readResolve()).
http://static.springsource.org/spring/docs/3.0.0.RC2/reference/html/ch07s08.html
Cheers.
You are absolutely right - #Autowired fields will be wired in an #Configurable annotated class even outside of a Spring container, assuming that you have a AspectJ infrastructure in place.
You have noted a good catch though, #Value fields are processed by a Spring bean post processor(AutowiredAnnotationBeanPostProcessor), which resolves the #Value annotated fields. It does not act on objects instantiated outside of the container though - so in short, the #Autowired fields should get wired in, but #Value properties will not.
Doing
MyObj obj = new MyObj()
means that obj is not managed by spring, so it will not do autowiring.
Only way to do that is to obtain instance from an application context. For example:
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
MyObj obj = context.getBean("myBean");
I don't think it is possible to use new operator and ask spring to autowire properties. I think 1 way to solve this is to get a static reference to applicationContext and create a prototype scoped bean.
#Component
public class ApplicationContextLocator {
private static ApplicationContext applicationContext;
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
public ApplicationContextLocator() {
super();
}
#Autowired
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
ApplicationContextLocator.applicationContext = applicationContext;
}
}
#Scope(BeanDefinition.SCOPE_PROTOTYPE)
#Component
public class MyObj {
.....
}
public aMethodSomewhereElse(){
MyObj obj = ApplicationContextLocator.getApplicationContext().getBean(MyObj.class)
assertNotNull(obj.getAField());
}