Spring returns null beans after initialization - java

I have a situation I cannot explain.
I am trying to create a RMI server that will call Spring services, but I cannot bind the beans to the rmi registry because they all are nulls.
The code is like this:
public class RMIServer {
private static final Logger LOG = LoggerFactory.getLogger(RMIServer.class);
public static void main(final String[] args) throws RemoteException, AlreadyBoundException {
final Registry registry = LocateRegistry.createRegistry(RmiConstants.RMI_PORT);
final ApplicationContext ctx = new AnnotationConfigApplicationContext(RmiConfiguration.class);
for (final String key : ctx.getBeansOfType(BaseRmi.class).keySet()) {
LOG.info("Registering {}...", key);
registry.bind(key, (BaseRmi) ctx.getBean(key));
}
LOG.info("RMI server was started...");
}
}
The Spring configuration class is:
#Configuration
#ImportResource({ "classpath*:app-context.xml" })
public class RmiConfiguration {
#Bean
AccountRmi accountRmi() {
try {
return new AccountRmiImpl();
} catch (final RemoteException e) {
return null;
}
}
}
The bean that I want to instantiate is this:
public class AccountRmiImpl extends BaseRmi implements AccountRmi {
private static final long serialVersionUID = 5798106327227442204L;
private final static Logger LOG = LoggerFactory.getLogger(AccountRmiImpl.class.getName());
#Autowired
private AccountService accountService;
public AccountRmiImpl() throws RemoteException {
super();
}
#Override
public List<PersonType> getPersonTypes() throws AppException {
return accountService.getPersonTypes();
}
}
The BaseRmi is:
public abstract class BaseRmi extends UnicastRemoteObject {
protected BaseRmi() throws RemoteException {
super();
}
private static final long serialVersionUID = 9115163829282749718L;
}
The interface for this bean is this:
public interface AccountRmi extends AccountFacade, java.rmi.Remote {
}
where the AccountFacade contains the business logic.
What I saw is that if I remove the java.rmi.Remote interface on the AccountRmi interfaces declaration the bean gets instantiated but I need that interface for the remote lookup. No errors are getting displayed in the logs. Does spring has a limitation for multiple interfaces on a bean declaration or it's just because of the java.rmi.Remote interfaces ?
I can provide further details if requested.
Many thanks,
Daniel

Related

How to instantiate a service class in a non component class

I have my service class which does a post call. I would like to instantiate that bean/ autowire it to create a object in another class which is not a component or configuration class.
#Service
public class SavePayload {
// Rest Post Call implementation
}
public class PayloadRecord
implements Record {
private String payload;
PayloadProcessor payloadProcessor = new PayloadProcessor();
public PayloadRecord(String payload) {
this.payload = payload;
}
#SneakyThrows
#Override
public boolean isValid() throws ValidationException {
payloadProcessor.savePayload(payload);
return true;
}
#Override
public byte[] getBytes(Charset charset) {
return payload.getBytes(StandardCharsets.UTF_8);
}
#Override
public String getID() {
return payload;
}
#Override
public String toString() {
return payload;
}
private static class PayloadProcessor {
#Autowired
private SavePayload savePayload;
}
}
I'm using a template which will do the record processing. As soon as I got message received I'm assigning it to Payload in Payload Record which is non component class. I would like to initialize the SavePayload service. Save payload service is returning null.
Create an application context aware class so you can get the current context, something like:
#Component
public class ContextAwareClass implements ApplicationContextAware {
private static ApplicationContext ctx;
public static ApplicationContext getApplicationContext() {
return ctx;
}
#Override
public void setApplicationContext(ApplicationContext applicationContext) {
ctx = applicationContext;
}
}
Then, just get the context and get the bean like:
public class YourRegularNoSpringComponentClass {
public void doSomething() {
System.out.println(ContextAwareClass
.getApplicationContext()
.getBean("savePayload")
);
}
}
Above will print the bean if it exist in your context. In your case you would simple use it rather than print it.
Hope this helps!
You will have to create an instance of ApplicationContext
You can explore
AnnotationConfigApplicationContext applicationContext= new AnnotationConfigApplicationContext();
and then use.
SavePayload savePayload = applicationContext.getBean("savePayload");

Spring Bean Factory Using Class Name

I have an interface/implementation like so:
public interface Processor {
void processMessage(Message m);
}
#Component
public class FooAProcessor implements Processor {
private FooA fooA;
public FooAProcessor(FooA fooA) {
this.fooA = fooA;
}
#Override
public void processMessage(Message m) {
//do stuff
}
}
#Component
public class FooBProcessor implements Processor {
private FooA fooA;
public FooBProcessor(FooA fooA) {
this.fooA = fooA;
}
#Override
public void processMessage(Message m) {
//do stuff
}
}
The FooA bean is simple, like this:
#Component
public class FooA {
//stuff
}
And the message class:
public class Message {
private Class clazz;
}
I am pulling messages off a queue. I need to provide a concrete Processor to handle the different types of messages appropriately. Here's the message receiver:
public class MessageReceiver {
public void handleMessage(Message m) {
Processor processor = //get concrete implementation from Message clazz
processor.processMessage(m);
}
}
How exactly can I use the class name/object to define a concrete implementation of Processor?
My first thought was to develop some sort of a factory that takes in a class and provides the concrete implementation. Something like this:
#Component
public class ProcessorFactory {
private FooAProcessor fooAProcessor;
private FooBProcessor fooBProcessor;
public ProcessorFactory(FooAProcessor fooAProcessor, FooBProcessor fooBProcessor) {
this.fooAProcessor = fooAProcessor;
this.fooBProcessor = fooBProcessor;
}
public Processor getFactory(Class clazz) {
if(clazz.isAssignableFrom(FooAProcessor.class)) {
return fooAProcessor;
}
}
}
Or to use the application context like this:
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.getBean(clazz);
Is this the best way to go about this problem? Is there a better practice?
You can inject ApplicationContext into your factory and get beans from there:
#Component
public class Factory {
#Autowired ApplicationContext applicationContext;
public Object getBean(String beanName) {
return applicationContext.getBean(beanName);
}
}
Or you can put your processors into map and get them from it:
#Component
public class ProcessorFactory {
private final Processor fooAProcessor;
private final Processor fooBProcessor;
private final Map<Class<T extends Processor>, Processor> beanMap;
public ProcessorFactory (Processor fooAProcessor, Processor fooBProcessor) {
this.fooAProcessor = fooAProcessor;
this.fooBProcessor = fooBProcessor;
this.beanMap = new HashMap(2);
}
#PostConstruct
public void init() {
beanMap.put(FooAProcessor.class, fooAProcessor);
beanMap.put(FooBProcessor.class, fooBProcessor);
}
public Processor getProcessor(Class<T extends Processor> clazz) {
return beanMap.get(clazz);
}
}
I recommend to not rely on class when working with spring context but use beanNames instead.

Akka SyncWriteJournal no matching arguments

So I have an Akka SyncWriteJournal (still in progress) and while unit testing the persistence I always get this error:
java.lang.IllegalArgumentException: no matching constructor found on class com.example.CustomJournal for arguments []
I have one constructor for CustomJournal which takes a few arguments necessary for the persistence to work. If I add an empty constructor to solve the error message the test throws and NPE because it needs fields that should be initiated in the constructor.
Why does it call the empty constructor (I never do it) by itself? And how can I solve this problem?
Code:
Class which creates actors:
public class AkkaActors {
private final ActorSystem actorSystem;
private final ActorRef journal;
private final ActorRef akkaPersistence;
public AkkaActors(JdbcTemplate jdbcTemplate, ObjectMapper objectMapper) {
this.actorSystem = ActorSystem.create("akkaSystem");
this.akkaPersistence = actorSystem.actorOf(Props.create(AkkaPersistence.class), "akkaPersistence");
this.journal = actorSystem.actorOf(Props.create(CustomJournal.class, jdbcTemplate, objectMapper, actorSystem), "customJournal");
}
Akka persistence actor:
public class AkkaPersistence extends UntypedPersistentActor {
private final static String PERSISTENCE_ID = "persistent_actor";
public AkkaPersistence() {
}
#Override
public void onReceiveRecover(Object msg) throws Exception {
if (msg instanceof String) {
System.out.println("msg");
}
}
#Override
public void onReceiveCommand(Object msg) throws Exception {
if (msg instanceof String) {
final String message = (String) msg;
persist(message, new Procedure<String>() {
#Override
public void apply(String message ) throws Exception {
getContext().system().eventStream().publish(message );
}
});
} else {
unhandled(msg);
}
}
#Override
public String persistenceId() {
return PERSISTENCE_ID;
}
}
Custom journal class (without contents of implemented methods):
public class CustomJournal extends SyncWriteJournal {
JdbcTemplate jdbcTemplate;
ObjectMapper objectMapper;
ActorSystem actorSystem;
public CustomJournal(JdbcTemplate jdbcTemplate, ObjectMapper objectMapper, ActorSystem actorSystem) {
this.jdbcTemplate = jdbcTemplate;
this.objectMapper = objectMapper;
this.actorSystem = actorSystem;
}
Test class:
#RunWith(SpringJUnit4ClassRunner.class)
#Transactional
public class AkkaActorsTest{
#Autowired
private JdbcTemplate jdbcTemplate;
#Autowired
private ObjectMapper objectMapper;
#Test
public void test() throws OperationNotSupportedException {
AkkaActors actors = new AkkaActors(jdbcTemplate, objectMapper);
actors.persist("test");
}

#Autowired and static method

I have #Autowired service which has to be used from within a static method. I know this is wrong but I cannot change the current design as it would require a lot of work, so I need some simple hack for that. I can't change randomMethod() to be non-static and I need to use this autowired bean. Any clues how to do that?
#Service
public class Foo {
public int doStuff() {
return 1;
}
}
public class Boo {
#Autowired
Foo foo;
public static void randomMethod() {
foo.doStuff();
}
}
You can do this by following one of the solutions:
Using constructor #Autowired
This approach will construct the bean requiring some beans as constructor parameters. Within the constructor code you set the static field with the value got as parameter for constructor execution. Sample:
#Component
public class Boo {
private static Foo foo;
#Autowired
public Boo(Foo foo) {
Boo.foo = foo;
}
public static void randomMethod() {
foo.doStuff();
}
}
Using #PostConstruct to hand value over to static field
The idea here is to hand over a bean to a static field after bean is configured by spring.
#Component
public class Boo {
private static Foo foo;
#Autowired
private Foo tFoo;
#PostConstruct
public void init() {
Boo.foo = tFoo;
}
public static void randomMethod() {
foo.doStuff();
}
}
You have to workaround this via static application context accessor approach:
#Component
public class StaticContextAccessor {
private static StaticContextAccessor instance;
#Autowired
private ApplicationContext applicationContext;
#PostConstruct
public void registerInstance() {
instance = this;
}
public static <T> T getBean(Class<T> clazz) {
return instance.applicationContext.getBean(clazz);
}
}
Then you can access bean instances in a static manner.
public class Boo {
public static void randomMethod() {
StaticContextAccessor.getBean(Foo.class).doStuff();
}
}
What you can do is #Autowired a setter method and have it set a new static field.
public class Boo {
#Autowired
Foo foo;
static Foo staticFoo;
#Autowired
public void setStaticFoo(Foo foo) {
Boo.staticFoo = foo;
}
public static void randomMethod() {
staticFoo.doStuff();
}
}
When the bean gets processed, Spring will inject a Foo implementation instance into the instance field foo. It will then also inject the same Foo instance into the setStaticFoo() argument list, which will be used to set the static field.
This is a terrible workaround and will fail if you try to use randomMethod() before Spring has processed an instance of Boo.
The easiest way to create a static context is naturally, when the application starts up. This will prevent the need for an unnatural implementation with an additional class.
#SpringBootApplication
public class MyApplication {
private static ApplicationContext appContext;
public static void main(String[] args) {
appContext = SpringApplication.run(MyApplication.class, args);
}
public static ApplicationContext getAppContext() {
return appContext;
}
}
Then, anywhere you need to access a bean statically, you can use the ApplicationContext to get the instance of the class.
public class Boo {
public static void randomMethod() {
MyApplication.getAppContext()
.getBean(Foo.class).doStuff();
}
}
Regards..
It sucks but you can get the bean by using the ApplicationContextAware interface. Something like :
public class Boo implements ApplicationContextAware {
private static ApplicationContext appContext;
#Autowired
Foo foo;
public static void randomMethod() {
Foo fooInstance = appContext.getBean(Foo.class);
fooInstance.doStuff();
}
#Override
public void setApplicationContext(ApplicationContext appContext) {
Boo.appContext = appContext;
}
}
This builds upon #Pavel's answer, to solve the possibility of Spring context not being initialized when accessing from the static getBean method:
#Component
public class Spring {
private static final Logger LOG = LoggerFactory.getLogger (Spring.class);
private static Spring spring;
#Autowired
private ApplicationContext context;
#PostConstruct
public void registerInstance () {
spring = this;
}
private Spring (ApplicationContext context) {
this.context = context;
}
private static synchronized void initContext () {
if (spring == null) {
LOG.info ("Initializing Spring Context...");
ApplicationContext context = new AnnotationConfigApplicationContext (io.zeniq.spring.BaseConfig.class);
spring = new Spring (context);
}
}
public static <T> T getBean(String name, Class<T> className) throws BeansException {
initContext();
return spring.context.getBean(name, className);
}
public static <T> T getBean(Class<T> className) throws BeansException {
initContext();
return spring.context.getBean(className);
}
public static AutowireCapableBeanFactory getBeanFactory() throws IllegalStateException {
initContext();
return spring.context.getAutowireCapableBeanFactory ();
}
}
The important piece here is the initContext method. It ensures that the context will always get initialized. But, do note that initContext will be a point of contention in your code as it is synchronized. If your application is heavily parallelized (for eg: the backend of a high traffic site), this might not be a good solution for you.
Use AppContext. Make sure you create a bean in your context file.
private final static Foo foo = AppContext.getApplicationContext().getBean(Foo.class);
public static void randomMethod() {
foo.doStuff();
}

How to inject with Guice `Module` where constructor accepts Class?

The title describes my problem.
E.g.
public class EntryDAOModule extends AbstractModule {
#Override
protected void configure() {
bind(EntryDAO.class).to(EntryDTOMongoImpl.class); // what should this be?
}
}
As shown, what should be the parameter to .to, given the below:
public class GenericDAOMongoImpl<T, K extends Serializable> extends BasicDAO<T, K> {
public GenericDAOMongoImpl(Class<T> entityClass) throws UnknownHostException {
super(entityClass, ConnectionManager.getDataStore());
}
}
public class EntryDAOMongoImpl extends GenericDAOMongoImpl<EntryDTOMongoImpl, ObjectId> implements EntryDAO<EntryDTOMongoImpl> {
private static final Logger logger = Logger.getLogger(EntryDAOMongoImpl.class);
#Inject
public EntryDAOMongoImpl(Class<EntryDTOMongoImpl> entityClass) throws UnknownHostException {
super(entityClass);
}
...
}
How can I instantiate the EntryDAOMongoImpl class like so:
Injector injector = Guice.createInjector(new EntryDAOModule());
this.entryDAO = injector.getInstance(EntryDAO.class); // what should this be?
What you are going to need here is to create a factory. Using assisted injection can help you here.
You can see my previous post regarding assisted injection
but here's the exact solution for your case:
EntryDAOMongoImpl:
public class EntryDAOMongoImpl extends GenericDAOMongoImpl<EntryDTOMongoImpl, ObjectId> implements EntryDAO<EntryDTOMongoImpl> {
private static final Logger logger = Logger.getLogger(EntryDAOMongoImpl.class);
#Inject
public EntryDAOMongoImpl(#Assisted Class<EntryDTOMongoImpl> entityClass) throws UnknownHostException {
super(entityClass);
}
...
}
Factory:
public interface EntryDAOFactory {
public EntryDAOMongoImpl buildEntryDAO(Class<EntryDTOMongoImpl> entityClass);
}
Module:
public class EntryDAOModule extends AbstractModule {
#Override
protected void configure() {
//bind(EntryDAO.class).to(EntryDAOMongoImpl.class); // what should this be?
FactoryModuleBuilder factoryModuleBuilder = new FactoryModuleBuilder();
install(factoryModuleBuilder.build(EntryDAOFactory.class));
}
}
Usage:
Injector injector = Guice.createInjector(new EntryDAOModule());
EntryDAOFactory factory = injector.getInstance(EntryDAOFactory.class);
this.entryDAO = factory.buildEntryDAO(entityClass);
If you are going to be using the EntryDAOMongoImpl as a singelton (natural usage of a singleton imo) then you can do the following without assisted injection within your module:
public class EntryDAOModule extends AbstractModule {
#Override
protected void configure() {
EtnryDTOMongoImpl dto = new EntryDTOMongoImpl(TargetEntry.class); //guessing here
bind(EntryDAO.class).toInstance(new EntryDAOMongoImpl(dto)); // singleton
}
}
Let me know if that helps

Categories

Resources