Akka SyncWriteJournal no matching arguments - java

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");
}

Related

Factory design patter Spring Boot double bean

#Component
public abstract class CommandBase {
#Autowired
WebServiceProxy nbiService;
#Autowired
OperationCacheRepository cacheRepository;
public CommandBase(
WebServiceProxy nbiService,
OperationCacheRepository cacheRepository) {
this.nbiService = nbiService;
this.cacheRepository = cacheRepository;
}
public abstract void executeSPV(SpeedTestDTO stDTO) throws NBIException;
public abstract long executeGPV(long guid, OperationCache operationCache) throws NBIException;
#Slf4j
public class DownloadDiagnosticsCommand extends CommandBase {
public DownloadDiagnosticsCommand(WebServiceProxy nbiService, OperationCacheRepository cacheRepository) {
super(nbiService, cacheRepository);
}
#Override
public void executeSPV(SpeedTestDTO stDTO) throws NBIException {
// some executable code
}
#Override
public long executeGPV(long guid, OperationCache operationCache) throws NBIException {
// some executable code
}
}
#Slf4j
public class UploadDiagnosticsCommand extends CommandBase {
public UploadDiagnosticsCommand(WebServiceProxy nbiService, OperationCacheRepository cacheRepository) {
super(nbiService, cacheRepository);
}
#Override
public void executeSPV(SpeedTestDTO stDTO) throws NBIException {
// some executable code
}
#Override
public long executeGPV(long guid, OperationCache operationCache) throws NBIException {
//some executable code
}
}
#Component
public class RFACommandFactory {
#Autowired
WebServiceProxy nbiServiceProxy;
#Autowired
OperationCacheRepository cacheRepository;
public final CommandBase createCommand(final String measureType) {
if ("download".equalsIgnoreCase(measureType)) {
return new DownloadDiagnosticsCommand(nbiServiceProxy, cacheRepository);
} else if ("upload".equalsIgnoreCase(measureType)) {
return new UploadDiagnosticsCommand(nbiServiceProxy, cacheRepository);
}
return null;
}
}
Calling method executeSPV from abstract class
#RestController
#RequestMapping("/rfa/speedtest/v1")
#Slf4j
public class Controller {
#Autowired
CommandBase command;
#Autowired
RFACommandFactory rfaCommandFactory;
#PostMapping(value = "{id}", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
#ResponseBody
private ResponseEntity<String> post(
#PathVariable String assetId,
#RequestBody Payload payload) {
log.info("Received new payload:{}", payload);
command = rfaCommandFactory.createCommand(speedTestDTO.getType());
try {
command.executeSPV(speedTestDTO);
} catch (NBIException e) {
log.info("NBIException", e);
return new ResponseEntity(payload, HttpStatus.BAD_REQUEST);
}
return new ResponseEntity(payload, HttpStatus.CREATED);
}
}
If I remove #Componet from Upload and Download classes I receive error I need to add Bean for abstrcat class CommndBase
If I use #Compoment on Upload and Download classes I receive dual Bean is useed...
Field command in .Controller required a single bean, but 2 were found:
You should not use #Component for abstract class, because Spring context will not be able to initialize that bean. You should remove it then.
Another thing is the way you want to implement a factory pattern here - I recommend you the way described here: https://stackoverflow.com/a/39361500/14056755, refactored version https://stackoverflow.com/a/55060326/14056755.

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");

Autowired object populated using ThreadLocalTargetSource does not populate for every class

My Spring Boot application implements the TenantStore example for storing data in ThreadLocalTargetSource detailed in this link
#Bean(destroyMethod = "destroy")
public ThreadLocalTargetSource threadLocalTenantStore() {
ThreadLocalTargetSource result = new ThreadLocalTargetSource();
result.setTargetBeanName("tenantStore");
return result;
}
The working example allows for the TenantStore object to be set and injected by the Spring Framework. My version of the TenantFilter class described in that article sets the properties of the TenantStore object whenever a Servlet request is made
#Autowired
private TenantStore tenantStore;
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
try {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication != null) {
String token = (String) request.getAttribute(ACCESS_TOKEN_VALUE);
if (token != null) {
OAuth2AccessToken oAuth2AccessToken = tokenStore.readAccessToken(token);
if (oAuth2AccessToken.getAdditionalInformation() != null) {
String tenantName = (String) oAuth2AccessToken.getAdditionalInformation().get("tenant");
storeTenantInThread(tenantName);
}
}
}
chain.doFilter(request, response);
} catch (ResourceNotFoundException e) {
log.error(e.getMessage());
} finally {
clearTenant();
}
}
private void storeTenantInThread(String tenantName) {
tenantStore.setName(tenantName);
}
private void clearTenant() {
tenantStore.clear();
}
I then have a number of services where TenantStore is autowired and in each of these services the TenantStore contains the information that was populated in the doFilter() method. Except for one class. For some reason the properties of the TenantStore in this class are still null. The name of the class affected is MyCacheService and the architecture is as follows:
#RestController
#RequestMapping("/here")
public class MyController {
#Autowired
private MyService myService
#GetMapping
public ResponseEntity myGetMethod(#RequestParam("text") String text) {
myService.myMethod(text);
return new ResponseEntity(Http.OK);
}
}
#Service
public class MyService {
#Autowired
private TenantStore tenantStore;
#Autowired
private MyOtherService myOtherService;
public void myMethod(String text) {
System.out.println(tenantStore.getName()); //works - prints name
myOtherService.myOtherMethod(text);
}
}
#Service
public class MyOtherService {
#Autowired
private TenantStore tenantStore;
#Autowired
private Map<String, MyComponent> myComponents;
public void myOtherMethod(String text) {
System.out.println(tenantStore.getName()); //works - prints name
MyComponent useThisComponent = myComponents.get("componentName");
useThisComponent.myComponentMethod(text);
}
}
#Component("componentName")
public class MyComponent {
#Autowired
private TenantStore tenantStore;
#Autowired
private MyCacheService myCacheService;
public void myComponentMethod(String text) {
System.out.println(tenantStore.getName()); //works - prints name
entityAliasCacheService.myCacheMethod(String text);
}
}
#Service
public class MyCacheService {
#Autowired
private TenantStore tenantStore;
public void myCacheMethod(String text) {
System.out.println(tenantStore.getName()); //DOES NOT WORK - tenantStore object is not null but the name property is
}
}
From what I can guess, for some reason the TenantStore in MyCacheService is being populated in a different thread, though I've no idea why.
I noticed similar behaviour. I fixed the issue by adding a bean dependancy
#Service
#DependsOn("proxiedThreadLocalTargetSource") // asks Spring to first load proxy bean
public class MyCacheService {
where proxiedThreadLocalTargetSource bean is defined like in the OP's example -
#Primary
#Bean(name = "proxiedThreadLocalTargetSource")
public ProxyFactoryBean proxiedThreadLocalTargetSource(ThreadLocalTargetSource threadLocalTargetSource) {
ProxyFactoryBean result = new ProxyFactoryBean();
result.setTargetSource(threadLocalTargetSource);
return result;
}
So, by adding the dependancy, Spring knows that it should load MyCacheService bean after the proxiedThreadLocalTargetSource. Without this dependancy, I noticed that TenantStore got injected instead of the proxy bean.
Getting instance of TenantStore from org.springframework.context.ApplicationContext
First implement ApplicationContextAware like as below
#Component
public class ApplicationContextUtil implements ApplicationContextAware {
private static ApplicationContext context;
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
context = applicationContext;
}
public static ApplicationContext context() {
return context;
}
}
And your MyCacheService Will be like this:
public class MyCacheService {
public void myCacheMethod(String text) {
TenantStore tenantStore = ApplicationContextUtil.context().getBean(TenantStore.class);
System.out.println(tenantStore.getName());
}
}

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.

Spring returns null beans after initialization

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

Categories

Resources