NullPointerException when injecting EJB in JBoss - java

I'm trying to implement a singleton class that manages properties from my database. However, I'm getting a nullPointerException when I try to inject my database bean. Here's my code:
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.ejb.EJB;
import javax.ejb.Stateless;
..
#Stateless
public class Properties {
public static volatile Properties instance;
private static Map<String, String> properties = new HashMap<String, String>();
#EJB(WHAT_TO_DO_HERE)
private DatabasePersisterLocal databasePersister;
public static Properties getInstance() {
if (instance == null) {
synchronized (Properties.class) {
if (instance == null) {
instance = new Properties();
}
}
}
return instance;
}
private Properties() {
System.out.println("starting");
System.out.println(databasePersister); //null
//initializing
}
}
I'm exporting my project as a jar, and later, when I try to get the instance of Properties, I get that a starting printed and then a nullPointerException. When I try to inject the same EJB (DatabasePersisterLocal) from my other project, I get no error. What am I doing wrong?

Regardless the issue about bean injection that you are facing, I would like to clarify that is not posible to implement a Singleton with an EJB at least in the way you are trying to do it.
The reason is that the ejb instances are handled by the container. The EJB's Thread Model specifies that every request will be managed by an available EJB's instance, which was previously instantiated and allocated to an ejb list (pool).
However if you are using EJB 3.1, it is posible to use the annotation #Singleton which indicates to container that has to create just one EJB's instance .

Related

How to assign a value from application.properties to a static variable?

I am using Spring MVC. I have a UserService class annotated with #Service that has a lot of static variables. I would like to instantiate them with values from the application.properties file.
For example in application.properties I have: SVN_URL = http://some.url/repositories
Then in the class there is: #Value("${SVN_URL}") private static String SVN_URL
I get the Instantiation of bean failed; nested exception is java.lang.ExceptionInInitializerError
I have also tried #Autowired private static Environment env;
And then: private static String SVN_URL=env.getProperty("SVN_URL");
It gives the same error.
Think about your problem for a second. You don't have to keep any properties from application.properties in static fields. The "workaround" suggested by Patrick is very dirty:
you have no idea when this static field is modified
you don't know which thread modifies it's value
any thread at any time can change value of this static field and you are screwed
initializing private static field that way has no sense to me
Keep in mind that when you have bean controlled by #Service annotation you delegate its creation to Spring container. Spring controls this bean lifecycle by creating only one bean that is shared across the whole application (of course you can change this behavior, but I refer to a default one here). In this case any static field has no sense - Spring makes sure that there is only one instance of UserService. And you get the error you have described, because static fields initialization happens many processor-cycles before Spring containers starts up. Here you can find more about when static fields are initialized.
Suggestion
It would be much better to do something like this:
#Service
public class UserService {
private final String svnUrl;
#Autowired
public UserService(#Value("${SVN_URL}") String svnUrl) {
this.svnUrl = svnUrl;
}
}
This approach is better for a few reasons:
constructor injection describes directly what values are needed to initialize the object
final field means that this value wont be changed after it gets initialized in a constructor call (you are thread safe)
Using #ConfigurationProperties
There is also another way to load multiple properties to a single class. It requires using prefix for all values you want to load to your configuration class. Consider following example:
#ConfigurationProperties(prefix = "test")
public class TestProperties {
private String svnUrl;
private int somePort;
// ... getters and setters
}
Spring will handle TestProperties class initialization (it will create a testProperties bean) and you can inject this object to any other bean initialized by Spring container. And here is what exemplary application.properties file look like:
test.svnUrl=https://svn.localhost.com/repo/
test.somePort=8080
Baeldung created a great post on this subject on his blog, I recommend reading it for more information.
Alternative solution
If you need somehow to use values in static context it's better to define some public class with public static final fields inside - those values will be instantiated when classloader loads this class and they wont be modified during application lifetime. The only problem is that you won't be able to load these values from Spring's application.properties file, you will have to maintain them directly in the code (or you could implement some class that loads values for these constants from properties file, but this sounds so verbose to the problem you are trying to solve).
Spring does not allow to inject value into static variables.
A workaround is to create a non static setter to assign your value into the static variable:
#Service
public class UserService {
private static String SVN_URL;
#Value("${SVN_URL}")
public void setSvnUrl(String svnUrl) {
SVN_URL = svnUrl;
}
}
Accessing application.properties in static member functions is not allowed but here is a work around,
application.properties
server.ip = 127.0.0.1
PropertiesExtractor.java
public class PropertiesExtractor {
private static Properties properties;
static {
properties = new Properties();
URL url = new PropertiesExtractor().getClass().getClassLoader().getResource("application.properties");
try{
properties.load(new FileInputStream(url.getPath()));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
public static String getProperty(String key){
return properties.getProperty(key);
}
}
Main.class
public class Main {
private static PropertiesExtractor propertiesExtractor;
static{
try {
propertiesExtractor = new PropertiesExtractor();
} catch (UnknownHostException e) {
e.printStackTrace();
}
}
public static getServerIP(){
System.out.println(propertiesExtractor.getProperty("server.ip")
}
}
static String profile;
#Value("${spring.profiles.active:Unknown}")
private void activeProfile(String newprofile) {
profile = newprofile;
};
In order to gain static access to Spring Boot properties you can create a Properties Holder Component which implements the Command Line Runner interface. The command line runner interface executes run() upon component instantiation by Spring Boot.
Since we have autowired access to our properties object in the PropertiesHolder component, it is possible to assign the autowired properties to a static Properties class variable upon CommandLineRunner execution of the run() method.
At this point any class can statically call PropertiesHolder.getProperties() to access the contents of Spring Boot properties values.
PropertiesHolder.class:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
#Component
public class PropertiesHolder implements CommandLineRunner {
//Spring Boot Autowired Properties Object
#Autowired MyProperties myAutowiredProperties;
//Statically assigned Properties Object
private static MyProperties properties;
//Hide constructor (optional)
private PropertiesHolder(){}
public static MyProperties getProperties() throws NullPointerException{
if(PropertiesHolder.properties == null)
throw new NullPointerException("Properites have not been initialized by Spring Application before call.");
return PropertiesHolder.properties;
}
//Use to assign autowired properties to statically allocated properties
public static void makeAvailable(MyProperties myAutowiredProperties){
PropertiesHolder.properties = myAutowiredProperties;
}
//Spring Boot command line runner autoexecuted upon component creation
//which initializes the static properties access
public void run(String... args) {
PropertiesHolder.makeAvailable(myAutowiredProperties);
}
}
MyProperties.class
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
//Example: your_properties_file_prefix.properties
#ConfigurationProperties(prefix = "YOUR_PROPERTIES_FILE_PREFIX")
#Component
#Data
public class MyProperties {
private String property1;
private String property2;
private String property3;
}
At least one more simple solution with configuration file:
#Configuration
public class YourStaticPropertyConfiuration {
public static String PROPERTY_NAME;
#Value("${propertyName}")
public void setProperty(final String propertyName) {
PROPERTY_NAME = propertyName;
}
}
Use PROPERTY_NAME anywhere as static variable
For all those who, for whatever reason, want to provide setting properties imported from files as static properties, here is a solution that is as simple and safe as possible.
The Problem:
Spring Boot unfortunately doesn't provide a simple way to import properties from a file and bind them as static properties to a class. One possible solution to achieve that anyway would be to set the static properties using `#Value` annotations like this:
public class GlobalProperties {
public static String NAME;
#Value("${configs.boss.name}")
public void setName(String name) {
NAME = name;
}
}
However, this approach would mean that the static properties cannot be declared as final.And we certainly don't want that.
The Solution:
application.yml:
configs:
boss:
name: "Leeloo Multipass"
ConfigProperties.java:
#Validated
#ConfigurationProperties(prefix = "configs")
public record ConfigProperties(#NotNull Boss boss) {
public static final String BOSS_NAME = BOSS.NAME;
private static class Boss {
private static String NAME;
public Boss(String name) {
NAME = name;
}
}
}
The solution is based on the assumption that Spring Boot builds the configuration objects first, and the properties' configuration objects first of all. So at the time Spring Boot adds the prepared objects as Bean to the context, the nested classes are already setup and the static properties initialization of ConfigProperties can access the static properties of the nested classes (which still are not final, but also not accessible from outside). This way it is possible to provide all properties declared as static final. Unless Spring Boot doesn't decide to change its internal initialization process, everything is cream & cookie.
This approach was tested with Spring Boot 3 and Java 17. It is of course possible to provide the properties additionally via the configs-bean. For that, the properties of the nested classes must be explicitly specified and their corresponding getters must be implemented. In this case, some simplification can be achieved by using records instead of classes.

Error on creating custom log4j Appender

I'm trying to create a custom Appender that will persist logs to the database using JPA.
The thing is that I'm using PersistenceContext attribute like this
package com.foobar.logging;
import com.foobar.model.SysLog;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.apache.log4j.AppenderSkeleton;
import org.apache.log4j.MDC;
import org.apache.log4j.spi.LoggingEvent;
import javax.ejb.Stateless;
#Stateless
public class LogManager extends AppenderSkeleton {
#PersistenceContext(unitName = "primary")
private EntityManager em;
#Override
protected void append(LoggingEvent le) {
SysLog log = new SysLog();
log.setDescripcion(le.getMessage().toString());
if (MDC.get("IdUsuario") != null) {
log.setIdUsuario(MDC.get("IdUsuario").toString());
}
log.setSysAccionLog(null);
this.em.persist(log);
}
#Override
public void close() {
}
#Override
public boolean requiresLayout() {
return false;
}
}
Now when I'm deploying the WAR to JBoss AS 7.1, it fails, and I get the error:
java.lang.VerifyError: class com.foobar.logging.LogManager$Proxy$_$$_Weld$Proxy$ overrides final method getName.()Ljava/lang/String;
How can I use CDI to inject my EntityManager inside an AppenderSkeleton? Has anyone accomplished JPA persistance in an AppenderSkeleton using CDI?
I also tried not using CDI, but since every other object in my app uses it (JAX-RS classes), it collapses.
EJBs are proxies. AppenderSkeleton has a getName method that is final. I think for your use case, you need to implement Appender directly. This will avoid the bean method getName
However, I have to question the idea of trying to make an appendar an EJB. How are you instantiating it?

How to use dependency injection in JAXB unmarshalled objects?

I have a factory class
#ApplicationScoped /* 'ApplicationScoped' is not a must */
class MyFactory {
#Inject
private IService aService;
...
}
And an JAXB annotated class
#XmlRootElement(name = "item")
class AnItem {
#Inject
MyFactory myFactory;
...
}
AnItem is instantiated by JAXB from an XML file.
The problem is that myFactory is null. If I replace this by
...
MyFactory myFactory = new MyFactory();
...
then myFactory.aService is null.
How can I use dependency injection within classes created by JAXB?
The following solution is inspired by a Block of Adam Warski, see also BeanManager Javadoc
At first I'll need two utility methods:
import javax.enterprise.inject.spi.Bean;
import javax.enterprise.inject.spi.BeanManager;
import javax.naming.InitialContext;
import javax.naming.NamingException;
public class Utils {
public static BeanManager getBeanManager() {
try {
InitialContext initialContext = new InitialContext();
return (BeanManager) initialContext.lookup("java:comp/BeanManager");
} catch (NamingException e) {
throw new RuntimeException("Failed to retrieve BeanManager!", e);
}
}
public static <T> T getBean(Class<T> c) {
T result = null;
BeanManager bm = getBeanManager();
Set<Bean<?>> beans = bm.getBeans(c);
if (! beans.isEmpty()) {
Bean<?> bean = beans.iterator().next();
result = c.cast(bm.getReference(bean, c, bm.createCreationalContext(bean)));
}
return result;
}
}
Class AnItem has then to be changed like this:
#XmlRootElement(name = "item")
class AnItem {
MyFactory myFactory = Utils.getBean(MyFactory.class);
...
}
I think you have some code in the wrong class, which is causing dependencies to be around the wrong way, which in turn makes the objects difficult to construct correctly.
Item looks like a newable class (sometimes known as an entity). Newable classes are not created by your container, but are created by service classes. Jaxb is an example of a service. The service classes are created by your DI container.
I would re-evaluate your need to have Item hold a reference to myFactory. You have not shown this in your question, but there must be a method in Item that makes a call to something in myFactory.
This code should be moved out of Item into a different class (perhaps a new service) that accepts an item as a parameter.
CDI beans are supposed to be container managed, meaning if you use new to create them you don't get any of the container services (injection, interception, decorators, etc). You'd need to #Inject your factory class to have the injection work correctly.

Can't get #Singleton to do anything

Running on JBoss AS7, I have this:
import javax.inject.Singleton;
#Singleton
public class Connections {
private final List<AtmosphereResource> connections = new ArrayList<AtmosphereResource>();
public void add(AtmosphereResource event) {
connections.add(event);
}
}
and this:
import javax.inject.Inject;
public class PubSubAtmosphereHandler extends AbstractReflectorAtmosphereHandler {
#Inject
private Connections connections;
#Override
public void onRequest(AtmosphereResource event) throws IOException {
[...]
connections.add(event); // <---
}
NPE on the designate line. After reading countless pages and examples, this is one of the ways that is repeated dozens of times, yet it doesn't work. I have the empty beans.xml, placed in my WEB-INF. What am I missing here ?
After some research, it turns out that Atmosphere provides (currently broken) hooks for this kind of functionality. That means it IS possible to simply use your normal annotations and have it work with Atmosphere, despite the 'foreign' instantiation.
If you know where your code will be deployed, you can simply overwrite the default noop InjectorProvider class from Atmosphere by having a class with the same name in the same package and having it provide the proper Injector.
I am adding code for JBoss AS7 at the end of this answer, as well as links to code that is supposed to work on Google Guice and Spring, which I have not tested myself.
If you need your code to work on multiple platforms, you will probably need to figure out how to detect what you are running on and then return the appropriate Injector. Since I'm not very familiar with Guice and Spring, I'll leave that exercise to the reader.
Dirty 'first draft' code for JBoss AS7 (remember that this has to go into the declared package to overwrite the default noop provider):
package org.atmosphere.di;
import java.util.NoSuchElementException;
import java.util.ServiceLoader;
import javax.enterprise.context.spi.CreationalContext;
import javax.enterprise.inject.spi.BeanManager;
import javax.enterprise.inject.spi.InjectionTarget;
import javax.naming.InitialContext;
import javax.naming.NamingException;
public class InjectorProvider {
private InjectorProvider() {}
public static Injector getInjector() {
return LazyProvider.INJECTOR;
}
private static final class LazyProvider {
private static final Injector INJECTOR;
static {
Injector injector = new Injector() {
#Override public void inject(final Object o) {
try {
final BeanManager bm = (BeanManager) new InitialContext().lookup("java:comp/BeanManager");
final CreationalContext cc = bm.createCreationalContext(null);
final InjectionTarget it = bm.createInjectionTarget(bm.createAnnotatedType(o.getClass()));
it.inject(o, cc);
cc.release();
} catch (final NamingException e) {
e.printStackTrace();
}
}
};
try {
injector = ServiceLoader.load(Injector.class).iterator().next();
} catch (final NoSuchElementException e) {}
INJECTOR = injector;
}
}
}
Please note that the wrapping code is taken from the Atmosphere code base, and is a very bad way to do Singletons in Java. You probably don't want to use this 'as is' in production.
Guice injector, untested: https://github.com/Atmosphere/atmosphere/blob/atmosphere-1.0.x/extras/guice/src/main/java/org/atmosphere/guice/GuiceInjector.java
Spring injector, untested: https://github.com/Atmosphere/atmosphere/blob/atmosphere-1.0.x/extras/spring/src/main/java/org/atmosphere/spring/SpringInjector.java
What others are trying to say is that the lifecycle of the PubSubAtmosphereHandler must be controlled by the container (aka JBoss).
In other words the container is responsible for creating and initialising instances of PubSubAtmosphereHandler.
If you or your framework creates this object then the injections will not take place.
It might be possible to get BeanManager using jndi. Then you can get the bean from there.
BeanManager bm = initialContext.lookup("java:comp/BeanManager");
Bean<Connections> bean = (Bean<Connections>) bm.getBeans(Connections.class).iterator().next();
CreationalContext<Connections> ctx = bm.createCreationalContext(bean);
Connections connections = (Connections) bm.getReference(bean, Connections.class, ctx);
connections.add(event);

Spring: how to instantiate a Spring bean that takes a runtime parameter?

I've got a singleton Spring bean that creates a couple of tasks (java.util.concurrent.Callable's) at runtime to do its work in parallel. Right now, the Callable's are defined as inner classes in the singleton bean, and the singleton bean creates them simply by instantiating them with new Task(in), where in is a parameter known only at runtime.
Now I want to extract the inner Task class to a regular top-level class because I want to make the Task's call() method transactional, so I need it to be a Spring bean.
I guess I need to give my singleton some kind of factory of Tasks, but the tasks have to be prototype Spring beans that take a runtime value as a constructor parameter. How can I accomplish this?
Spring's bean factory and new are mutually exclusive. You can't call new and expect that object to be under Spring's control.
My suggestion is to inject those Tasks into the Singleton. Make them Spring beans, too.
You should recognize that the Task itself isn't going to be transaction, but its dependencies can be. Inject those into the Tasks and let Spring manage the transactions.
Another approach might be to use Spring's #Configurable annotation with load-time weaving, this way you can use new (instead of a bean factory) to create wired Callable's at runtime:
#Configurable
public class WiredTask implements Callable<Result> {
#Autowired
private TaskExecutor executor;
public WiredTask(String in) {
this.in = in;
}
public Result call() {
return executor.run(in);
}
}
#Bean #Scope("prototype")
public class TaskExecutor() {
#Transactional
public Result run(String in) {
...
}
}
// Example of how you might then use it in your singleton...
ExecutorService pool = Executors.newFixedThreadPool(3);
WiredTask task = new WiredTask("payload");
Future<Result> result = pool.submit(task);
See this article for more info. Note, you cannot use #Configurable and #Transactional in the same bean, hence the need for two classes. For that reason, this might not be the ideal solution if you have lots of different implementations of Callable (since you will need 2 classes for each one).
Your singleton bean can implement BeanFactoryAware and lookup beans from the containing spring factory.
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
public class MyBeanFactory implements BeanFactoryAware {
private BeanFactory beanFactory;
public void setBeanFactory(BeanFactory beanFactory)
throws BeansException {
this.beanFactory = beanFactory;
}
public Task createTask(Task in) {
return beanFactory.getBean("task",in);
}
}
///////////////
import java.util.concurrent.Callable;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.context.annotation.Scope;
import org.springframework.transaction.annotation.Transactional;
#Configurable // unless using xml based config
#Scope(value="prototype") // tell bean factory to create new instance each time
public class Task implements Callable<Object> {
private Object in;
public Task(Object in) {
super();
this.in = in;
}
#Transactional
public Object call() throws Exception {
//do real work
return in;
}
}
///

Categories