I need some help to find solution for my problem. I created 1 utility class and inject here some CrudRepositories. But repositoryies doesn't works fine here. They returns NullPointerException (Repositories works fine only in controllers).
Here is error and some code.
Error image
Once again, I note that such errors do not appear in the controller.
#Repository
public interface EventRepository extends CrudRepository<Event, Long> {
#Query(nativeQuery = true, value = "select * from events e order by e.id desc LIMIT 5")
List<Event> getEventsWithLimit();
}
#Service
public class CachedObject extends TimerTask {
#Autowired
EventRepository eventRepository;
#Autowired
MatchRepository matchRepository;
#Autowired
PlayerRepository playerRepository;
#Autowired
ImageRepository imageRepository;
List<Rank> ranking;
List<Image> image;
//Last 10 next Matches
List<Match> nextMatches;
//Last 10 results
List<Match> results;
List<PlayerOfTheWeek> playerOfTheWeek;
//Last 5 event
List<Event> events;
#Override
public void run() {
try{
refreshCache();
}
catch (Exception e){
e.printStackTrace();
}
}
public void refreshCache() throws Exception{
events = eventRepository.getEventsWithLimit();
image = imageRepository.getRandomImage();
results = matchRepository.getLastResult();
nextMatches = matchRepository.getLastMatches();
ranking = makeRanking();
...
}
...
}
Can you give me some tips for find solution guys?((
If you want to use solution TimerTask i think u need to create a constructor with needed autowired beans. But better solution in spring is to use #Scheduler annotation to periodically execute needed method. (more about Schedulers in spring https://spring.io/guides/gs/scheduling-tasks/)
Related
I have a Spring REST API I am developing that keeps returning a NullReferenceException for some reason. I can't figure out why. Here is my code:
The interface:
public interface InitiativesService {
InitiativeDto createInitiative(InitiativeDto initiativeDto);
}
The class that implements it:
public class InitiativeServiceImpl implements InitiativesService {
private final InitiativeRepository initiativeRepository;
#Autowired
public InitiativeServiceImpl(InitiativeRepository initiativeRepository)
{
this.initiativeRepository = initiativeRepository;
}
#Override
public InitiativeDto createInitiative(InitiativeDto initiativeDto) {
initiativeRepository.Save(initiativeDto);
}
The Repository class for communicating to the dB:
#Repository
public interface InitiativeRepository extends JpaRepository<Initiative, Long> {}
And lastly the controller:
public class InitiativesController {
private InitiativesService initiativesService;
public InitiativesController(InitiativesService initiativesService) {
this.initiativesService = initiativesService;
}
#PostMapping(produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<InitiativeDto> createInitiative(#Valid #RequestBody InitiativeDto initiative) {
log.info("Saving");
InitiativeDto createdInitiative = initiativesService.createInitiative(initiative);
return ResponseEntity.status(HttpStatus.CREATED).body(createdInitiative);
}
When I try running this and testing via Postman, it returns a NullPointerException. I debug it and I can see the initiativesService is null. I am confused as I have the same implementation for creating Users which works fine without this issue. Can anyone spot any problems I have here?
Add #Autowired annotation on your constructor to autowire your initiativeService
#Autowired
public InitiativesController(InitiativesService initiativesService) {
this.initiativesService = initiativesService;
}
I'm using Spring Rest. I have an Entity called Operator that goes like this:
#Entity
#Table(name = "operators")
public class Operator {
//various properties
private List<OperatorRole> operatorRoles;
//various getters and setters
#LazyCollection(LazyCollectionOption.TRUE)
#OneToMany(mappedBy = "operator", cascade = CascadeType.ALL)
public List<OperatorRole> getOperatorRoles() {
return operatorRoles;
}
public void setOperatorRoles(List<OperatorRole> operatorRoles) {
this.operatorRoles = operatorRoles;
}
}
I also have the corresponding OperatorRepository extends JpaRepository
I defined a controller that exposes this API:
#RestController
#RequestMapping("/api/operators")
public class OperatorController{
private final OperatorRepository operatorRepository;
#Autowired
public OperatorController(OperatorRepository operatorRepository) {
this.operatorRepository = operatorRepository;
}
#GetMapping(value = "/myApi")
#Transactional(readOnly = true)
public MyResponseBody myApi(#ApiIgnore #AuthorizedConsumer Operator operator){
if(operator.getOperatorRoles()!=null) {
for (OperatorRole current : operator.getOperatorRoles()) {
//do things
}
}
}
}
This used to work before I made the OperatorRoles list lazy; now if I try to iterate through the list it throws LazyInitializationException.
The Operator parameter is fetched from the DB by a filter that extends Spring's BasicAuthenticationFilter, and is then somehow autowired into the API call.
I can get other, non-lazy initialized, properties without problem. If i do something like operator = operatorRepository.getOne(operator.getId());, everything works, but I would need to change this in too many points in the code.
From what I understand, the problem is that the session used to fetch the Operator in the BasicAuthenticationFilter is no longer open by the time i reach the actual API in OperatorController.
I managed to wrap everything in a OpenSessionInViewFilter, but it still doesn't work.
Anyone has any ideas?
I was having this very same problem for a long time and was using FetchType.EAGER but today something has clicked in my head ...
#Transactional didn't work so I thought "if declarative transactions don't work? Maybe programmatically do" And they do!
Based on Spring Programmatic Transactions docs:
public class JwtAuthorizationFilter extends BasicAuthenticationFilter {
private final TransactionTemplate transactionTemplate;
public JwtAuthorizationFilter(AuthenticationManager authenticationManager,
PlatformTransactionManager transactionManager) {
super(authenticationManager);
this.transactionTemplate = new TransactionTemplate(transactionManager);
// Set your desired propagation behavior, isolation level, readOnly, etc.
this.transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
}
private void doSomething() {
transactionTemplate.execute(transactionStatus -> {
// execute your queries
});
}
}
It could be late for you, but I hope it helps others.
Let's say I have this code structure:
public class NotificationService {
public void send(Notification notification) {
// call other services and send the notification
}
}
public class OrderNotification implements Notification {
#Autowired
public TranslationService translationService;
private String orderNumber;
public OrderNotification(String orderNumber) {
this.orderNumber = orderNumber;
}
public String getMessage() {
return translationService.trans('notification.order', new Object[]{orderNumber});
}
}
So, my goal is to use the NotificationService in this way:
notificationService.send(new OrderNotification(orderNumber));
But I know that code above won't work, because of the translationService won't be resolved.
My goal is to pass custom parameters to my Notification classes and being able to use services inside that class. What is the best way to do it in the Spring?
I know that below is not the correct answer to your question. It is however a bad design pattern to combine Entities and Services. An Entity should only contain information about the object and not business logic. A Service contains all the business logic.
You need to separate your Service from your Entity.
OrderNotification looks like a regular entity. The entity should not contain business logic. You need a specific service for the business logic.
public class OrderNotification implements Notification {
private String orderNumber;
public OrderNotification(String orderNumber) {
this.orderNumber = orderNumber;
}
public String getMessage() {
return "Order number: " + orderNumber;
}
//Getter & Setters
...
}
#Service
public class NotificationService {
#Autowired
public TranslationService translationService;
public void send(Notification notification) {
//I do not know what trans accepts, so I assume it can accept Notification
translationService.trans(notification.getMessage());
}
}
If you really need to combine the entity and service - Then I recommend this approach:
#Service
public class Master{
#Autowired
NotificationService notificationService
public void testMethod(){
Notification notification = notificationService.createOrder("order1");
notificationService.send(notification);
}
}
#Service
public class NotificationService {
#Autowired
public TranslationService translationService;
public Notification createOrder(String orderNumber){
return new OrderNotification(orderNumber, translationService);
}
public void send(Notification notification) {
// call other services and send the notification
notification.getMessage();
}
}
public class OrderNotification implements Notification {
private TranslationService translationService;
private String orderNumber;
//I have changed this constructor to accept TranslationService.
public OrderNotification(String orderNumber, TranslationService translationService) {
this.orderNumber = orderNumber;
this.translationService = translationService;
}
public String getMessage() {
return translationService.trans('notification.order', new Object[]{orderNumber});
}
}
You have few options available:
Configure AOP and load time weaving to process Spring annotations on objects created with new keyword. This is explained in the docs 5.8.1. Using AspectJ to dependency inject domain objects with Spring.
Declare OrderNotification as a prototype scoped bean and obtain each instance from the context using BeanFactory.getBean(Class<T> requiredType, Object... args) method.
String orderNumber = "123";
OrderNotificaton = factory.getBean(OrderNotificaton.class, orderNumber);
Drop the #Autowired and use plain constructor injection.
public OrderNotification(TranslationService translationService, String orderNumber) {
this.translationService = Objects.requireNonNull(translationService);
this.orderNumber = Objects.requireNonNull(orderNumber);
}
If you only require simple #Autowired I'd go with option 3. It's the simplest approach and makes writing unit tests easier as you don't have to depend on Spring.
I am wanting to stream some data out the database after a Spring Batch Tasklet step
public class TaskletUpdateAll implements Tasklet {
#Autowired
private AdRepository adRepository;
#Override
public RepeatStatus execute(StepContribution sc, ChunkContext cc) {
return RepeatStatus.FINISHED;
}
#AfterStep
#Transactional(readOnly = true)
public ExitStatus afterStepMethod(StepExecution stepExecution) {
try (Stream<Pair<String, String>> adStream = adRepository.streamAll();) {
adStream.forEach((Pair ad) -> {
// Process ad
});
}
return ExitStatus.COMPLETED;
}
}
Despite the fact the method that calls the stream is annotated with #Transactional(readOnly = true) it still returns the following error message:
Caused by: org.springframework.dao.InvalidDataAccessApiUsageException:
You're trying to execute a streaming query method without a
surrounding transaction that keeps the connection open so that the
Stream can actually be consumed. Make sure the code consuming the
stream uses #Transactional or any other way of declaring a (read-only)
transaction.
The AdRepository class follows the advice from here so the streamAll method looks like this:
#Repository
public interface AdRepository extends JpaRepository<Ad, Long> {
#QueryHints(value = #QueryHint(name = "HINT_FETCH_SIZE", value = "" + Integer.MIN_VALUE))
#Query(value = "SELECT href, provider FROM ad", nativeQuery = true)
Stream<Pair<String, String>> streamAll();
...
}
I have also made sure to include the #EnableTransactionManagement annotation in the configuration class for the Job as told to by the documentation.
...
#Configuration
#EnableTransactionManagement
public class MainTaskletsConfig {
...
Any idea if what I am doing is even possible and if it is what I am doing wrong?
I am having a problem related to JPA & some hibernate listeners I configured to index/deindex the Db entities into Elastic Search. The problem is basically that the listener onPostInsert method is called even if I throw an exception in the method where I am persisting an entity and this method is marked as #Transactional(rollbackFor = {Throwable.class}). My configuration is as follows.
The listener class:
public class ElasticSearchEventListener implements PostDeleteEventListener,
PostInsertEventListener, PostUpdateEventListener {
#Override
public void onPostInsert(PostInsertEvent event) {
log.debug("Listener indexing entity");
try {
updateElasticSearch(event.getEntity());
} catch (Exception e) {
log.debug("Error indexing object from listener");
e.printStackTrace();
}
}
.......
}
The listener configured class:
#Service #Log4j
public class ListenerConfigurerImpl implements ListenerConfigurer {
#Autowired
private EntityManagerFactory entityManagerFactory;
#Autowired
private ElasticSearchEventListener listener;
#PostConstruct #Override
public void registerListeners() {
log.debug("Registering event listeners");
HibernateEntityManagerFactory hibernateEntityManagerFactory = (HibernateEntityManagerFactory) this.entityManagerFactory;
SessionFactoryImpl sessionFactoryImpl = (SessionFactoryImpl) hibernateEntityManagerFactory.getSessionFactory();
EventListenerRegistry registry = sessionFactoryImpl.getServiceRegistry().getService(EventListenerRegistry.class);
registry.getEventListenerGroup(EventType.POST_COMMIT_INSERT).appendListener(listener);
.......
}
}
A service class:
#Service #Log4j
public class ConversationServiceImpl implements ConversationService {
#Override
#Transactional(rollbackFor = {Throwable.class})
public void quotePackage(Long userId, CustomQuoteDTO dto) {
......
Conversation conversation = Conversation.createAndAssign(user, agency, type, subject);
conversation = conversationRepository.save(conversation);
Long conversationId = conversation.getId();
if (1 == 1) throw new RuntimeException();
}
}
Based on this configuration, I would be expecting that the conversation entity is not saved neither in the DB nor Elastic Search. The entity is not persisted in the DB which is correct but for some reason the "onPostInsert" is still executing... and I get the entity in Elastic Search even if it is not in the Database.
Any ideas? I am a bit lost.
Thanks in advance.
EDIT 1 ------
I have found this bug from 2006 and it is still open that seems to be my problem: https://hibernate.atlassian.net/browse/HHH-1582
Is this supposed to work this way?
The pull request added here https://hibernate.atlassian.net/browse/HHH-1582 fixes this issue.