Why does Spring App crash when using #autowire [duplicate] - java

This question already has an answer here:
What is a NoSuchBeanDefinitionException and how do I fix it?
(1 answer)
Closed 3 years ago.
I am using latest version of IntelliJIDEA CE edition (11.0.4).
There is one thing that I could not find anywhere, and it is a blocker for my further improvements with Java/Spring.
Controller:
import com.example.demo.classes.SaveToFile;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
#RestController
public class MainController {
#Autowired protected SaveToFile saveToFile;
//#Autowired SaveToDb saveToDb;
#RequestMapping("/start")
public String whatever(#RequestParam(value="name", defaultValue="World") String name) {
saveToFile.save(name);
return "something";
//return new SaveToFile(name);
}
}
Class:
import com.example.demo.interfaces.ISave;
public class SaveToFile implements ISave {
private String filename = "Vlad";
#Override
public void save(String name) {
System.out.println("Saving " + name + " to file.");
}
public String getFilename(){
return filename;
}
}
Class Interface:
public interface ISave {
void save(String name);
}
Nothing fancy, just to get a grasp of Spring and Java.
Inside my Controller, when I try to use
#Autowired protected SaveToFile saveToFile;
I get an error that prevents app from starting. Here is the error:
Execution failed for task ':DemoApplication.main()'.
Process 'command '/Library/Java/JavaVirtualMachines/openjdk-11.0.2.jdk/Contents/Home/bin/java''
finished with non-zero exit value 1
If I comment that out, I can instantiate my class with "new", but thats not the point.
I have tried changing SDK's in the Project Structure menu option. but to no avail.
Maybe worth to point out, that similar project I also work on in Kotlin, has no issues at all. I tried to Mimick the "Kotlin" settings, but nothing.
Does anyone have any clue as to what is going on in here?

You should either annotate the SaveToFile class with #Component, or create a bean of that type (annotated #Bean) in any config class for the #Autowired to work.

First, make SaveToFile a Spring-managed bean:
#Component
public class SaveToFile implements ISave {
// [...]
}
Second, autowire the bean:
#RestController
public class MainController {
#Autowired protected ISave saveToFile;
// [...]
}

Spring needs to pick that one up as a component, otherwise it doesn't really know where to Autowire it from.
Try annotating it with a #Service and make the class itself is within Component Scanner's reach.

Related

Not able to rollback DB changes in Aspect in Spring boot application

I have written one aspect around a service class. In the aspect, I am doing some operation in the before section, which I would like to be rolled back if some exception occurs in the enclosed service method.
The service class is as follows:
#Service
#Transactional
class ServiceA {
...
public void doSomething() {
...
}
...
}
The aspect is as follows:
#Aspect
#Order(2)
public class TcStateManagementAspect {
...
#Around(value = "applicationServicePointcut()", argNames = "joinPoint")
public Object process(ProceedingJoinPoint joinPoint)
throws Throwable {
...
*/Before section */
do some processing and persist in DB
...
Object object = joinPoint.proceed();
...
do some post-processing
}
}
I am seeing an exception in the service method is not rolling back the DB operation in the Begin Section. I tried putting #Transactional on #Around, but it did not help.
In this context, I have gone through the following posts:
Spring #Transactional in an Aspect (AOP)
Custom Spring AOP Around + #Transactional
But I am not able to get any concrete idea regarding how to achieve this. Could anyone please help here? Thanks.
Like I said in my comment, what your around advice does must be declared transactional too. You cannot do that directly, because #Transactional internally uses Spring AOP via dynamic proxies. However, Spring AOP aspects cannot be the target of other aspects. But you can simply create a new helper #Component which you delegate your advice's action to.
Let us assume that the goal is to log the arguments of the #Transactional method targeted by your aspect. Then simply do this:
package com.example.managingtransactions;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
#Aspect
#Component
public class TxLogAspect {
private final static Logger logger = LoggerFactory.getLogger(TxLogAspect.class);
#Autowired
TxLogService txLogService;
#Pointcut(
"#annotation(org.springframework.transaction.annotation.Transactional) && " +
"!within(com.example.managingtransactions.TxLogService)"
)
public void applicationServicePointcut() {}
#Around("applicationServicePointcut()")
public Object process(ProceedingJoinPoint joinPoint) throws Throwable {
logger.info(joinPoint.toString());
// Delegate to helper component in order to be able to use #Transactional
return txLogService.logToDB(joinPoint);
}
}
package com.example.managingtransactions;
import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import java.util.Arrays;
import java.util.List;
/**
* Helper component to delegate aspect advice execution to in order to make the
* advice transactional.
* <p>
* Aspect methods themselves cannot be #Transactional, because Spring AOP aspects
* cannot be targeted by other aspects. Delegation is a simple and elegant
* workaround.
*/
#Component
public class TxLogService {
#Autowired
private JdbcTemplate jdbcTemplate;
#Transactional
public Object logToDB(ProceedingJoinPoint joinPoint) throws Throwable {
jdbcTemplate.update(
"insert into TX_LOG(MESSAGE) values (?)",
Arrays.deepToString(joinPoint.getArgs())
);
return joinPoint.proceed();
}
public List<String> findAllTxLogs() {
return jdbcTemplate.query(
"select MESSAGE from TX_LOG",
(rs, rowNum) -> rs.getString("MESSAGE")
);
}
}
See? We are passing through the joinpoint instance to the helper component's own #Transactional method, which means that the transaction is started when entering that method and committed or rolled back depending on the result of joinPoint.proceed(). I.e. what the aspect helper writes to the DB itself will also be rolled back if something goes wrong in the aspect's target method.
BTW, because I never used Spring transactions before, I simply took the example from https://spring.io/guides/gs/managing-transactions/ and added the two classes above. Before, I also added this to schema.sql:
create table TX_LOG(ID serial, MESSAGE varchar(255) NOT NULL);
Next, I added made sure that TxLogService is injected into AppRunner:
private final BookingService bookingService;
private final TxLogService txLogService;
public AppRunner(BookingService bookingService, TxLogService txLogger) {
this.bookingService = bookingService;
this.txLogService = txLogger;
}
If then at the end of AppRunner.run(String...) you add these two statements
logger.info("BOOKINGS: " + bookingService.findAllBookings().toString());
logger.info("TX_LOGS: " + txLogService.findAllTxLogs().toString());
you should see something like this at the end of the console log:
c.e.managingtransactions.AppRunner : BOOKINGS: [Alice, Bob, Carol]
c.e.managingtransactions.AppRunner : TX_LOGS: [[[Alice, Bob, Carol]]]
I.e. you see that only for the successful booking transaction a log message something was written to the DB, not for the two failed ones.

micronaut #RequestScope - not creating bean per incoming http-request

I have a class the following class as RequestScope bean:
#RequestScope
class RequestContext {
private String requestId;
private String traceId;
private String authorisedId;
private String routeName;
// few more fields
#Inject RequestContext(SecurityContext securityContext) {
this.requestId = UUID.randomUUID().toString();
if(securityService.getAuthentication().isPresent()){
this.authorisedId = (securityService
.getAuthentication().get()).getUserId().toString();
}
}
/* to be updated in controller method interceptors */
public void updateRouteName(String name){
this.routeName = name;
}
The idea is to have an object containing the REST request level custom data accessible across the application, the scope of the this obviously should be within the current request. This can be used for say.. logging - whenever devs log anything from the application, some of the request meta data goes with it.
I am not clear what the #RequestScope bean really is:
From its definition - my assumption is it is created for every new http-request and same instance is shared for the life of that request.
when is it constructed by Micronaut ? Is it immutable ?
Across multiple requests I can see the same requestId ( expecting new UUID for every request)
Is it the right use-case for #RequestScope bean?
I was running into an issue regarding #RequestScope so I'll post an answer here for others.
I was trying to inject a #RequestScope bean into an HTTP filter, set a value in the bean, and then read it later from another bean. For example
#RequestScope
class RequestScopeBean() {
var id: Int? = null
}
#Filter
class SetRequestScopeBeanHere(
private val requestScopeBean: Provider<RequestScopeBean>
) {
override fun doFilterOnce(request: HttpRequest<*>, chain: ServerFilterChain): Publisher<MutableHttpResponse<*>> {
requestScopeBean.get().id = // id from Http Request
}
}
#Singleton
class GetRequestScopeBeanHere(
private val requestScopeBean: Provider<RequestScopeBean>
) {
fun getIdFromRequestScopeBean() {
println(requestScopeBean.get().id)
}
}
In this example before any controller is executed my filter (SetRequestScope) is called, this will set requestScopeBean.id but the key is that the request scope bean must be wrapped in a javax.inject.Provider, otherwise setting the field won't work.
Down the line, when GetRequestScopeBeanHere::getIdFromRequestScopeBean is called it'll have access to the requestScopeBean.id set earlier
This is intentional by Micronaut:
https://github.com/micronaut-projects/micronaut-core/issues/1615
when is it constructed by Micronaut ?
A #RequestScope bean is created during request processing, the first time the bean is needed.
Is it immutable ?
It could be. You get to decide if the bean is mutable or not when you write the class. As written in your example, RequestContext is mutable. If you remove the updateRouteName method, that bean would be immutable.
Is it the right use-case for #RequestScope bean?
I don't think so, but that is really an opinion based question.
EDIT: Based On Comments Added Below
See the project at https://github.com/jeffbrown/rscope.
https://github.com/jeffbrown/rscope/blob/2935a4c1fc60f350198d7d3c1dbf9a7eedd333b3/src/main/java/rscope/DemoController.java
package rscope;
import io.micronaut.http.annotation.Controller;
import io.micronaut.http.annotation.Get;
#Controller("/")
public class DemoController {
private final DemoBean demoBean;
public DemoController(DemoBean demoBean) {
this.demoBean = demoBean;
}
#Get("/doit")
public String doit() {
return String.format("Bean identity: %d", demoBean.getBeanIdentity());
}
}
https://github.com/jeffbrown/rscope/blob/2935a4c1fc60f350198d7d3c1dbf9a7eedd333b3/src/main/java/rscope/DemoBean.java
package rscope;
import io.micronaut.runtime.http.scope.RequestScope;
#RequestScope
public class DemoBean {
public DemoBean() {
}
public int getBeanIdentity() {
return System.identityHashCode(this);
}
}
https://github.com/jeffbrown/rscope/blob/2935a4c1fc60f350198d7d3c1dbf9a7eedd333b3/src/test/java/rscope/DemoControllerTest.java
package rscope;
import io.micronaut.http.client.RxHttpClient;
import io.micronaut.http.client.annotation.Client;
import io.micronaut.test.annotation.MicronautTest;
import org.junit.jupiter.api.Test;
import javax.inject.Inject;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
#MicronautTest
public class DemoControllerTest {
#Inject
#Client("/")
RxHttpClient client;
#Test
public void testIndex() throws Exception {
// these will contain the identity of the the DemoBean used to handle these requests
String firstResponse = client.toBlocking().retrieve("/doit");
String secondResponse = client.toBlocking().retrieve("/doit");
assertTrue(firstResponse.matches("^Bean identity: \\d*$"));
assertTrue(secondResponse.matches("^Bean identity: \\d*$"));
// if you modify DemoBean to be #Singleton instead of
// #RequestScope, this will fail because the same instance
// will be used for both requests
assertNotEquals(firstResponse, secondResponse);
}
}

How to measure service methods using spring boot 2 and micrometer

I started my first project on Spring Boot 2 (RC1). Thanks to the already good documentation this has not been to hard coming from Spring Boot 1.x.
However now that I want to integrate metrics I'm stumbeling. As far as I was able to find currently there is only documentation for the metrics shipped by default. But I'd like to also measure service level execution time as well as the time used in dynamodb.
EDIT
I'm looking for a solution using Micrometer, the library used in the new actuator library shipped with spring-boot 2.
Is there any guide on how this should be done? From this I read that there is no easy annotation based solution for arbitrary spring beans yet. Could s.o. give me an example / link to documentation on how a method like below could be metered?
#Service
#Timed
public class MyService {
public void doSomething() {
...;
}
}
#io.micrometer.core.annotation.Timed annotation seems to be out of order for custom calls due to reduction of scope, at it is mentioned in link in your question.
You need to manually setup an Aspect:
#Configuration
#EnableAspectJAutoProxy
public class AutoTimingConfiguration {
#Bean
public TimedAspect timedAspect(MeterRegistry registry) {
return new TimedAspect(registry);
}
}
This way method like this:
#Timed("GET_CARS")
public List<Car> getCars(){
return Lists.newArrayList();
}
will result in GET_CARS metric in /actuator/metrics (default) endpoint.
Here's a little sample which should get you going. There's more variants to Timer.record() which aren't shown here. (Also: Field injection only used for brevity.)
You don't have to put the called methods name into a tag. You can also make it part of the metric name itself. Just wanted to show what you could do.
Update 2018-03-12: As of Micrometer 1.0.0 a TimedAspect has been introduced so that you can also use the #Timed annotation. For now you need to register the Bean yourself. (You need to be cautious though when you have custom #Timed annotations on your Spring-MVC or Jersey resources.) This was already mentioned by Michal Stepan in a follow-up answer.
package io.github.mweirauch.micrometered.eval;
import java.util.concurrent.TimeUnit;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import io.micrometer.core.annotation.Timed;
import io.micrometer.core.aop.TimedAspect;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Timer;
import io.micrometer.core.instrument.Timer.Sample;
#Configuration
#EnableAspectJAutoProxy
public class TimingStuff {
#Service
static class MyService {
#Autowired
private MeterRegistry registry;
public void helloManual() {
// you can keep a ref to this; ok to call multiple times, though
Timer timer = Timer.builder("myservice").tag("method", "manual").register(registry);
// manually do the timing calculation
long start = System.nanoTime();
doSomething();
timer.record(System.nanoTime() - start, TimeUnit.NANOSECONDS);
}
public void helloSupplier() {
Timer timer = Timer.builder("myservice").tag("method", "supplier").register(registry);
// execution of the method is timed internally
timer.record(() -> doSomething());
}
public void helloSample() {
Timer timer = Timer.builder("myservice").tag("method", "sample").register(registry);
// records time taken between Sample creation and registering the
// stop() with the given Timer
Sample sample = Timer.start(registry);
doSomething();
sample.stop(timer);
}
// TimedAspect adds "class" and "method" tags
#Timed(value = "myservice.aspect")
public void helloAspect() {
doSomething();
}
private void doSomething() {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
//
}
}
}
#Autowired
private MyService myService;
#Bean
TimedAspect timedAspect(MeterRegistry registry) {
return new TimedAspect(registry);
}
#Scheduled(fixedRate = 1000)
public void postConstruct() {
myService.helloManual();
myService.helloSupplier();
myService.helloSample();
myService.helloAspect();
}
}
In case you go for Prometheus, you'd end up with something like that:
# HELP myservice_seconds
# TYPE myservice_seconds summary
myservice_seconds_count{application="micrometered",method="manual",} 4.0
myservice_seconds_sum{application="micrometered",method="manual",} 0.200378014
myservice_seconds_max{application="micrometered",method="manual",} 0.050115291
myservice_seconds_count{application="micrometered",method="supplier",} 4.0
myservice_seconds_sum{application="micrometered",method="supplier",} 0.200393455
myservice_seconds_max{application="micrometered",method="supplier",} 0.05011635
myservice_seconds_count{application="micrometered",method="sample",} 4.0
myservice_seconds_sum{application="micrometered",method="sample",} 0.200527005
myservice_seconds_max{application="micrometered",method="sample",} 0.050250191
# HELP myservice_aspect_seconds
# TYPE myservice_aspect_seconds summary
myservice_aspect_seconds_count{application="micrometered",class="io.github.mweirauch.micrometered.eval.TimingStuff$MyService",method="helloAspect",} 4.0
myservice_aspect_seconds_sum{application="micrometered",class="io.github.mweirauch.micrometered.eval.TimingStuff$MyService",method="helloAspect",} 0.201824272
myservice_aspect_seconds_max{application="micrometered",class="io.github.mweirauch.micrometered.eval.TimingStuff$MyService",method="helloAspect",} 0.051014296

When and how to instantiate a Spring Bean in my Rest Api

First of all, I'm a relative noob to Spring Boot, so keep that in mind.
I've got a REST api in which I'm trying to minimize database calls for the same object and I've determined that using a Spring Bean scoped to the Request is what I want. Assuming that is correct, here is what I'm trying to do:
1) Controller takes in a validated PhotoImportCommandDto command
PhotoCommandController
#RequestMapping(method = RequestMethod.POST)
public ResponseEntity<?> importPhoto(#Valid #RequestBody PhotoImportCommandDto command){
...
}
2) PhotoImportCommandDto is validated. Note the custom #UserExistsConstraint which validates that the user exists in the database by calling a service method.
PhotoImportCommandDto
#Component
public class PhotoImportCommandDto extends BaseCommand {
#NotNull(message = "userId must not be null!")
#UserExistsConstraint
private Long userId;
...
}
What I would like to do is somehow set a Spring Bean of the user that is validated in the #UserExistsConstraint and reference it in various methods that might be called throughout a Http request, but I'm not really sure how to do that. Since I've never really created my own Spring Beans, I don't know how to proceed. I've read various guides like this, but am still lost in how to implement it in my code.
Any help/examples would be much appreciated.
You can use the #Bean annotation.
#Configuration
public class MyConfiguration {
#Bean({"validUser"})
public User validUser() {
User user;
//instantiate user either from DB or anywhere else
return user;
}
then you can obtain the validUser.
#Component
public class PhotoImportCommandDto extends BaseCommand {
#Autowired
#Qualifier("validUser")
private User validUser;
...
}
I don't really know how to make annotations in Java. Anyway, in Spring, checking where the User exists in the DataBase or not is one line of code:
userRepository.findOne(user) == null
That is accomplished by the Spring Data JPA project:
Create a JPA Entity User.
Set the spring.datasource.url and login/password in the
resources/application.properties.
Create this interface:
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
#Repository
public interface UserRepository extends CrudRepository<User, Long> {
}
Note, Spring implements it behind the scences.
Inject this interface into your RestController (or any other Spring bean):
private UserRepository userRepository ;
**constructor**(UserRepository ur){
userRepository = ur;
}
Note, a Spring Bean is any class annotated #Component (this includes stereotype annotations like Controller, Repository - just look up the contents of an annotation, it may use #Component internally) or returned from a method which is annotated #Bean (can only be on the Component or Configuration class). A Component is injected by searching the classpath, Bean is injected more naturally.
Also note, injecting is specifying #Autowired annotation on field or constructor, on a factory method, or on a setter. The documentation recommends that you inject required dependencies into constructor and non-required into the setter.
Also note, if you're injecting into a constructor and it is clean by the arguments, you may omit #Autowired annotation, Spring will figure it out.
Call its method findOne.
So, you can do one of the following:
Inject the userRepository into the #RestController constructor (as shown above). I would do that.
Inject the userRepository into the #Service (internally #Component) class that will do this sorts of thing for you. Maybe you can play with it to create an annotation.
p.s. Use #PostMapping instead of #RequestMapping(method = RequestMethod.POST)
p.p.s. If ever in doubt, go to the official documentation page and just press CTRL-F: http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/ Note the current word, that will always take you to the latest version.
p.p.p.s Each Spring project has its own .io webpage as well as quick Get Started Guides where you can quickly see the sample project with explanations expecting you to know nothing.
Hope that helps! :)
Don't forget to mark the answer as accepted if you wish
Using Jose's input, I took a bit of a different route.
Here's what I did:
I created a ValidatedUser class:
#RequestScope
#Component
public class ValidatedUser {
private UserEntity user;
public UserEntity getUser() {
return user;
}
public void setUser(UserEntity user) {
this.user = user;
}
}
and I also created a wrapper class HttpRequestScopeConfig to capture all variables to use over the course of an Http Request to the api.
#Component
public class HttpRequestScopeConfig {
#Autowired
private ValidatedUser validatedUser;
...
public UserEntity getValidatedUser() {
return validatedUser.getUser();
}
public void setValidatedUser(UserEntity validatedUser) {
this.validatedUser.setUser(validatedUser);
}
...
}
In my UserExistsConstraintValidator (which is the impl of #UserExistsConstraint, I set the validatedUser in the httpRequestScopeConfig:
public class UserExistsConstraintValidator implements ConstraintValidator<UserExistsConstraint, Long> {
//private Log log = LogFactory.getLog(EmailExistsConstraintValidator.class);
#Autowired
private UserCommandService svc;
#Autowired
private HttpRequestScopeConfig httpRequestScope;
#Override
public void initialize(UserExistsConstraint userId) {
}
#Override
public boolean isValid(Long userIdField, ConstraintValidatorContext context) {
try {
UserEntity user = svc.findUserOfAnyStatus((Long) userIdField);
if (user != null) {
httpRequestScope.setValidatedUser(user);
return true;
}
} catch (Exception e) {
//log.error(e);
}
return false;
}
}
Now, I can access these variables throughout the rest of my service layers by autowiring HttpRequestScopeConfig where necessary.

How can I inform my SpringBoot-Application of a class copy?

I've got a problem with #Autowiring being null. I am looking for advice how to model it the spring-boot-way.
My Soap-Services get really big using lots of Repository classes. This gives me a large list of #Autowired already. Now when I want to call a helper-class like HeaderValidator.class I can't instantiate and call it like a POJO. This because everything annotated #Autowiring in my HeaderValidator is null. I can make it work when I add #Autowired at line (1) and remove the content of (2) in SoapServiceImpl.
But this will end in a huge list of #Autowired annotated fields and this looks ugly. I want to prevent this even it works for now.
This Article mentions the #Configurable with AspectJ. But the Article is from 2013 and Spring-Boot has developed since. I tried the #Configurable solution but it didn't work in my case.
How can I inform my SpringBoot-Application of a class copy? Is the #Configurable-way still the only one? Or did I simply model the application wrong?
Application.class:
#SpringBootApplication
public class Application {
private static ApplicationContext ctx;
public static void main(String... args) {
ctx = SpringApplication.run(Application.class, args);
publishSoapServices();
}
SoapService.class (gets published when calling publishSoapServices() in Application.class):
public class SoapServiceImpl implements SoapService {
#Autowired
ProjectRepository projectRepo;
(1) "#Autowired"
HeaderValidator headerValidator;
#Override
public EventReport send(#WebParam(name = "header") HeaderType headerType,
#WebParam(name = "content") ContentType contentType) {
return storeServiceData(headerType, messageType);
}
private EventReport storeServiceData(HeaderType headerType, ContentType contentType) {
projectRepo.save(contentType);
(2) "HeaderValidator headerValidator= new HeaderValidator()"
return headerValidator.validate(headerType);
}
My problem class:
#Service
public class HeaderValidator {
#Autowired
ValidFieldsRepository validFieldsRepo; //<-- always null!
I managed to solve my problem. It was simply due to bad design. I went trough the application and configured #Configurableit correctly. Now it works all fine. Thanks to M.Deinum!

Categories

Resources