I have a problem scanning the consumer that I made as an inner class inside my serviceimpl.java
code below:
public class CredsServiceImpl implements CredsService {
#Service
public static class userCredsConsumer implements Consumer<Event<UserData>> {
private final Logger log = LoggerFactory.getLogger(userCredsConsumer.class);
#Autowired
EntityManager entityManager;
#Autowired
CredsDAO credsDAO;
public void accept(Event<UserData> notificationDataEvent) {
UserData notificationData = notificationDataEvent.getData();
entityManager.setEntityId(notificationData.getTenantId());
List<CredsDTO> credsUser = credsDAO.selectByUserId(notificationData.getUserId());
if(credsUser == null || credsUser.isEmpty()){
log.info("No Existing Credential Watcher Record for User [{}]", notificationData.getUserName());
}else{
credsDAO.deleteByUserId(notificationData.getUserId());
log.info("Creds Record for User [{}] is Deleted", notificationData.getUserName());
}
}
}
}
and I am trying to access it from the credentialconfig that I made
#Autowired
private EventBus eventBus;
#Autowired
UserCredsConsumer userCredsConsumer;
#PostConstruct
public void postConstruct() {
eventBus.on($("userCredsConsumer"), userCredsConsumer);
}
the problem I have right now is it is not going the the userCredsConsumer class that I made in the serviceimpl.
any insights would help.. if I don't make it as an inner class it is working fine. but if I make it as an inner class its not working properly.. but I really need this to be in an inner class for specific reasons in the business.
Related
I'm creating telegram bot with Spring-Boot. I have AscractState class:
public abstract class AbstractState {
boolean isInputIndeed = Boolean.FALSE;
public abstract void handleInput(BotContext context);
//another parts
}
And there is extend which is
#Slf4j
public class AgeInputState extends AbstractState {
#Autowired
ClientService clientService;
public AgeInputState(boolean isInputIndeed) {
super(isInputIndeed, State.AGE_INPUT);
}
#Override
public void handleInput(BotContext context) {
context.getClient().setAge(Integer.parseInt(context.getInput()));
clientService.updateUser(context.getClient());
}
}
But i have touble with ClientService. Which annotations on class i need to add for autowiring this fiels?
Since this class has a constructor which only accepts a boolean, I assume you're needing to make lots of them.
Spring won't know you're wanting to load these as spring beans if you call this constructor directly. So creating these through a factory of some sort would be one way to go. Something like:
#Configuration
public class AgeInputStateFactory {
private #Autowired ClientService clientService;
#Bean
#Scope("prototype") // Makes a new one each time...
public AgeInputState create(final boolean isInputIndeed) {
return new AgeInputState(this.clientService, isInputIndeed);
}
}
Along with a newly designed AgeInputState constructor which also takes the ClientService field.
public class AgeInputState extends AbstractState {
private final ClientService clientService;
// Package private constructor so that no one outside
// of this package will call it. This means you can
// (try your best to) limit the construction to the
// factory class.
AgeInputState(final ClientService clientService,
final boolean isInputIndeed) {
super(isInputIndeed, State.AGE_INPUT);
this.clientService = clientService;
}
}
And then all you would do is wherever you need to create these AgeInputState Objects, you would #Autowire the AgeInputStateFactory instance, and call the create method whenever you need one.
So I have my Subject class:
#Component
public class Subject<T extends Monitorable> {
#Autowired
private List<Observer<T>> observers;
public void fireListeners(T monitorable){
for (Observer<T> observer : observers) {
observer.doSome(monitorable);
}
}
}
Is that a way to create a new subject instance for each implementation of Monitorable like:
#Autowired
private Subject<Trip> tripSubject;
Trip is a Monitorable and it has its own observers
#Autowired
private Subject<Truck> truckSubject;
and truck as well
The problem is. It creates only one Subject with all observers mixed how to separate them without create a new subject class for each monitorable?
This is not the answer to your question, but maybe a solution for your problem: Spring 4.2 has a build in event (observer) mechanism :
#Autowire ApplicationEventPublisher publisher;
public void doSomething() {
...
//fire the event
publisher.publishEvent(new YourEvent());
...
}
Some other bean:
//This is the observer, it "catch" the event
#EventListener
public void handleOrderCreatedEvent(YourEvent your) {
...
}
It is pretty simple. You could do it in a few ways, one of them is just create #Configuration and defind separate method for each required instance.
First, do remove #Component annotation from Subject definition:
//#Component
public class Subject<T extends Monitorable> {
}
Second, do define custom configuration with #Configuration:
#Configuration
public class MonitorableConfiguration {
#Bean
public Subject<Trip> tripSubject() {
return new Subject<>();
}
#Bean
public Subject<Truck> documentSubject() {
return new Subject<>();
}
}
Third, do use #Qualified to select required instance of Subject bean:
#Service
public class BusinessLogicService {
#Autowired
#Qualifier("tripSubject")
private Subject<Trip> tripSubject;
#Autowired
#Qualifier("documentSubject")
private Subject<Truck> documentSubject;
}
NOTE
In this situation, I would reccomend to go a little bit further. It could be more readable from my point of view.
First, do remove #Component annotation from Subject definition:
//#Component
public class Subject<T extends Monitorable> {
}
Second, do declare separate class definition for all required types:
#Component
public class TripSubject extends Subject<Trip> {
}
#Component
public class TruckSubject extends Subject<Truck> {
}
Third use is as any other singletons cope beans:
#Service
public class BusinessLogicService {
#Autowired
private TripSubject tripSubject;
#Autowired
private TruckSubject documentSubject;
}
I improved oleg.cheredinik answer because there is no way to do it. Here's what I think is the best solution:
I changed Subject to receive Observer as construct params
public class Subject<T extends Monitorable> {
private final List<Observer<T>> observers;
public Subject(final List<Observer<T>> observers) {
this.observers = observers;
}
public void fireListeners(T monitorable){
for (Observer<T> observer : observers) {
observer.doSome(monitorable);
}
}
}
and then I created subject with SubjectSimpleFactory :
#Configuration
public class SubjectSimpleFactory {
#Bean
#Autowired(required = false)
public Subject<Trip> getTripSubject( Optional<List<Observer<Trip>>> observers){
return new Subject<>(getListenersIfPresent(observers));
}
#Bean
#Autowired(required = false)
public Subject<Truck> getTruckSubject( Optional<List<Observer<Truck>>> observers){
return new Subject<>(getListenersIfPresent(observers));
}
}
private static <M extends Monitorable> List<Observer<M>> getListenersIfPresent(
final Optional<List<Observer<M>>> observers )
{
return observers.isPresent() ? observers.get() : Collections.emptyList();
}
In this way my observers are not mixed and I only have to create one class without repeat code or subclass Subject and I can use generic type as qualifier as well
#Service
#Scope("prototype")
public class Subject<T extends Monitorable> {
}
#Component
public class RunSubject {
#Autowired
private Subject<Monitorable1> subject1;
#Autowired
private Subject<Monitorabl2> subject2;
public void run(ApplicationArguments args) throws Exception {
System.out.println(subject1);
System.out.println(subject2);
}
}
I have a controller class which is below. I have a TagRepository interface which extends JPA repository which I am using to save TagReader instance to my DB and it works fine when I use it in my controller class. However, when I try to use tagRepository in another class and try to save my TagReader object from there it throws a null pointer exception.
The following logic works fine.
#RestController
public class Controller {
#Autowired
TagRepository tagRepository;
#Autowired
Rfid6204Connection rfid6204Connection;
#RequestMapping(value = "/test")
public void testRepoController(){
String tagid = "0x3504ACE6E0040E5147D516A6";
String serial ="00333478";
String departure ="2017-12-22T12:16:58.857";
String type = "ISOC";
TagReader tagReader = new TagReader(tagid,serial,departure,type,"5");
tagRepository.save(tagReader);
}
}
The following logic throws a null pointer exception.
#component
public class Rfid6204Connection{
#Autowired
static TagRepository tagRepository;
public static void test(TagReader tag){
tagRepository.save(tag);
}
}
Can someone please tell me what the issue is?
I think you are using Rfid6204Connection.test as a static method. Spring doesn't work with Static methods. It works with Objects instantiated by the Spring Container. So change your Rfid6204Connection as below;
#Component
public class Rfid6204Connection{
#Autowired
private TagRepository tagRepository;
public void test(TagReader tag){
tagRepository.save(tag);
}
}
And use it wherever you want as below;
#Autowired
Rfid6204Connection rfid6204Connection;
// Within a method or constructor
rfid6204Connection.test(tag);
You made the Autowired field static and when the class loader loads the static values, the Spring context is not yet loaded and your object is not correctly initialized; remove the static keyword:
#Autowired
private TagRepository tagRepository;
you couldn't autowired static variables directly
then, you have some options.
first, autowired instance of TagRepository and after dependency injection
set a instance to static variable
#Component
public class Rfid6204Connection {
private static TagRepository sTagRepository;
#Autowired
private TagRepository tagRepository;
#PostConstruct
public void init() {
Rfid6204Connection.sTagRepository = tagRepository;
}
}
second prepare setter method of TagRepository and put a autowired
public class Rfid6204Connection {
private static TagRepository tagRepository;
#Autowired
public void setTagRepository(TagRepository tagRepository) {
Rfid6204Connection.tagRepository = tagRepository;
}
}
but originally ... you shoudn't autowire to static variables.
I have a Spring-boot Java application which streams data continuously from Kafka and saves it to the database Cassandra after applying business logic.
Below are the pseudo classes and functions which resemble my application fully.
KafkaStreamer
#Configuration
#EnableKafka
public class KafkaStreamer {
private static final Logger LOGGER = LoggerFactory.getLogger(MyDomain.class);
#Autowired
private MyController myController;
#KafkaListener(topics = "${my-topic}", group = "${my-group}")
public void streamFromKafka(String payload) {
myController.processPayload(payload);
LOGGER.info("I am continously streaming data from Kafka "
+ "and forwarding it to controller for further processing...!");
}
}
MyController
#Controller
public class MyController {
private static final Logger LOGGER = LoggerFactory.getLogger(MyDomain.class);
#Autowired
private MyService myService;
public void processPayload(String payload) {
myService.applyBusinessLogic(payload);
LOGGER.info("Send to service for business-logic processing");
}
}
MyService
#Service
public class MyService {
private static final Logger LOGGER = LoggerFactory.getLogger(MyDomain.class);
#Autowired
private MyDomain myDomain;
public void applyBusinessLogic(String payload) {
myDomain.saveToDatabase(payload);
LOGGER.info("Applied business-logic");
}
}
MyDomain
#Repository
public class MyDomain {
private static final Logger LOGGER = LoggerFactory.getLogger(MyDomain.class);
#Autowired
private CassandraOperations cassandraTemplate;
/** The session. */
private Session session = null;
public void saveToDatabase(String payload) {
saveToTableA(payload);
saveToTableB(payload);
// Hello, I have saved data to database
LOGGER.info("Saved data to database");
}
private void saveToTableB(String payload) {
if (session == null)
session = cassandraTemplate.getSession();
session.execute(payload);
}
private void saveToTableA(String payload) {
if (session == null)
session = cassandraTemplate.getSession()
session.execute(payload);
}
}
The above pseudo code resembles my original application fully.
As you can see I do not have any class level variables other than logger, some auto-wired variable and cassandra session in MyDomain class
According to my knowledge, auto-wire by default in spring-boot is singleton.
I am passing payload (which is my message from Kafka) from one class to another class in function argument rather setting as the class level property of other class.
My question is,
Is my above application architecture or code thread safe ?.
Can Autowire create problem as by default it gives singleton reference of a class ( a point to note here is I do not have any class level variables other than logger and auto-wire variable)
If you feel if there exists a better way or anything, please feel free to write.
Many thanks from me.
Your solution stops to be thread-safe if you start to mutate the state of the shared object.
For example if you'd have a payload property in the MyDomain singleton Spring bean and set its value in the saveToDatabase and a bit later (even in the same method) consult it, that would be mutation and your code won't be thread-safe.
For example:
#Repository
public class MyDomain {
private String payload;
public void saveToDatabase(String payload) {
this.payload = payload;
saveToTableA();
saveToTableB();
}
private void saveToTableA() {
tableA.save(this.payload);
}
In this case when several threads call your saveToDatabase concurrently with different values, there is no guarantee what value you really will save to the DB in the saveToTableA().
My application have the follow layer:
- Facade
- Business Object
- Repository (Spring JPA Data)
Let's suppose the follow classes:
#Component
public class MessageFacade implements MessageService {
#Autowired
private GarageBO garageBO;
#Autowired
private MessageBO messageBO;
public void createFeedbackMessage(...) {
messageBO.createFeedbackMessage(...);
garageBO.createFeedback(...);
}
}
#Component
public class ServiceOrderFacade implements ServiceOrderService {
#Autowired
private ServiceOrderBO serviceOrderBO;
#Autowired
private MessageBO messageBO;
#Autowired
private GarageBO garageBO;
public void createServiceOrder(...) {
serviceOrderBO.createServiceOrder(...);
messageBO.createFeedbackMessage(...);
garageBO.createFeedback(...);
}
}
Observing the createFeedbackMessage method in MessageFacade i have:
1) The createFeedbackMessage method in MessageBO it's responsible to create an email with the feedback survey LINK;
2) The createFeedbackMessage method in garageBO creates the Feedback ENTITY with the questions and responses;
On createServiceOrder method in ServiceOrderFacade i need to call an method of ServiceOrderBO and after i need to have the same behavior of createFeedbackMessage method in MessageFacade.
Is it a bad idea to create a dependency between ServiceOrderFacade -> MessageFacade ?
The code would be:
#Component
public class ServiceOrderFacade implements ServiceOrderService {
#Autowired
private ServiceOrderBO serviceOrderBO;
#Autowired
private MessageBO messageBO;
#Autowired
private GarageBO garageBO;
public void createServiceOrder(...) {
serviceOrderBO.createServiceOrder(...);
getMessageService().createFeedbackMessage(...);
}
}
If you think in DRY(don't repeat yourself) you have an problem. You can create another layer like a common that is dependency of Business Object layer and will be created once and will be used in your entire BO if U want