RequestScoped objects don't seem to be reinitialized for new requests - quarkus

This is the request scoped object. Also tried without the RequestScopeContext not being request scoped but just the attributes within it request scoped. Also tried with #Inject rather than #Produces.
#RequestScoped
public class RequestScopeContext {
#Produces
#RequestScoped
MessageHandlerContext messageHandlerContext = new MessageHandlerContext();
#Produces
#RequestScoped
MessageUtilCache messageUtilCache = new MessageUtilCache();
}
Tried these with #Inject as well as #Produces.
To be used by
#Provider
#ApplicationScoped
public class InterceptorServer {
private static final String INSTRUCTION_TYPE_REQUEST = "REQUEST";
private static final String INSTRUCTION_TYPE_RESPONSE = "RESPONSE";
private static final String CONFIG_TYPE_FILTER = "FILTER";
private static final Logger LOGGER = LoggerFactory.getLogger(InterceptorServer.class);
#Inject
RequestScopeContext requestScopeContext;
#Inject
MessageUtilConfigurations messageHandlerConfigurations;
#RouteFilter(1)
void messageHandlerServerFilter(RoutingContext routingContext) {
Also tried with #Inject #Produces
RequestScopeContext requestScopeContext;
Also tried with #Inject #RequestScope
RequestScopeContext requestScopeContext;
Also tried with #Produces #RequestScope
RequestScopeContext requestScopeContext;
In all cases either the combinations of annotations weren't accepted or the MessageUtilCache still had values from previous requests.

Related

What will happen if i remove #Autowired from field/constructor injection but injecting that bean in another class

Suppose i have a class as,
#Repository
public class StudentServiceDao{
private final StudentClient client;
private final StudentValidator validator;
#Autowired <----
public StudentServiceDao(StudentClient studentClient){
client = studentClient;
validator = new StudentValidator(studentClient.getIdentifier());
}
public List<Student> getStudent(Request request){
StudentRS studentRS= client.getStudentList(request);
validator.validate(studentRS);
return StudentMapper.map(studentRS);
}
}
Now i have another class as,
#Component
public class StudentServiceDaoImpl{
#Autowired
private StudentServiceDao studentServiceDao;
public list<Student> retrieveStudent (Request request){
return studentServiceDao.getStudent(request);
}
}
Now if i remove #Autowired from StudentServiceDao what will happen and why ?
Autowiring can happen multiple ways.
For a few years now (currently 2020) all of these are valid ways to autowire dependencies:
Explicit constructor autowire annotation:
#Repository
public class StudentServiceDao {
private final StudentClient client;
private final StudentValidator validator;
#Autowired
public StudentServiceDao(StudentClient studentClient){
client = studentClient;
validator = new StudentValidator(studentClient.getIdentifier());
}
}
Implicit constructor autowire:
#Repository
public class StudentServiceDao {
private final StudentClient client;
private final StudentValidator validator;
public StudentServiceDao(StudentClient studentClient){
client = studentClient;
validator = new StudentValidator(studentClient.getIdentifier());
}
}
Explicit field autowire:
#Repository
public class StudentServiceDao {
#Autowired
private final StudentClient client;
#Autowired
private final StudentValidator validator;
}
Pick which ever one makes the most sense for you. I personally like implicit constructor. I think it makes instantiating the bean for testing easier with mocks. All types are valid.
5 or 6 years ago, before java config took over, there were other requirements like getters/setters needing to be present, xml files needing to specify all the beans, etc. But those are mostly gone and if you are working on a modern spring app you won't encounter them.
As to why, I have no idea, this is just how it is.

Object in bean constructor empty

I have exception-messages written down in the application.yml. They are pure text, which is later reformatted using java.text.MessageFormat.
I have got the following custom RuntimeException my service throws when login failed:
#Component
public class AccountLoginFailedException extends RuntimeException {
#Autowired
public AccountLoginFailedException(#Value("#(${authservice.exception-messages.login-failed})") final String message, #Qualifier(value = "Credentials") final Credentials credentials) {
super(MessageFormat.format(message, credentials.getUsername()));
}
}
My test, which solely tests the AccountController and mocks away the service behind it:
#RunWith(SpringRunner.class)
#ContextConfiguration(classes = AuthServiceTestConfiguration.class)
#WebMvcTest(AccountController.class)
public class AccountControllerTest {
#Autowired
private BeanFactory beanFactory;
#Autowired
private ObjectMapper objectMapper;
#Autowired
private TestHelper helper;
#MockBean
private AccountService accountService;
#Autowired
private JwtService jwtService;
#Autowired
private MockMvc mvc;
#Test
public void test_LoginFailed_AccountDoesNotExist() throws Exception {
// Given
final Credentials credentials = helper.testCredentials();
final String credentialsJson = objectMapper.writeValueAsString(credentials);
final AccountLoginFailedException loginFailedException = beanFactory.getBean(AccountLoginFailedException.class, credentials);
// When
given(accountService.login(credentials)).willThrow(loginFailedException);
// Then
mvc
.perform(
post("/login")
.accept(MediaType.APPLICATION_JSON_UTF8_VALUE)
.contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)
.content(credentialsJson))
.andExpect(status().isUnprocessableEntity())
.andExpect(jsonPath("$.data").value(equalTo(loginFailedException.getMessage())));
}
}
message contains the correct String. However: credentials contains just an empty object (not null) instead of the one created using helper.testCredentials().
Here is a slightly simplified TestHelper class I am using:
#TestComponent
public class TestHelper {
public static final String USERNAME = "SomeUsername";
public static final String PASSWORD = "SomePassword";
#Autowired
private BeanFactory beanFactory;
public Credentials testCredentials() {
final Credentials credentials = beanFactory.getBean(Credentials.class.getSimpleName(), Credentials.class);
credentials.setUsername(USERNAME);
credentials.setPassword(PASSWORD);
return credentials;
}
}
These custom exceptions are thrown by my application only and are always expected to contain the credentials (username) responsible for it. I also have a AccountExceptionsControllerAdvice-class, which just wraps these custom exceptions in a generic JSON response, exposing the error in a preferred manner.
How can I ensure that this particular instance of Credentials is inserted into the particular instance of AccountLoginFailedException? Or should I not be autowiring exceptions at all?
You could mock your Credentials component in your tests as follows:
#MockBean
private Credentials credentials;
#Before
public void before() {
when(credentials.getUsername()).thenReturn(USERNAME);
when(credentials.getPassword()).thenReturn(PASSWORD);
}

Injecting one MockBean into another

I have a typical SpringApplication which I am trying to test via MockMvc. The application contains some database calls and some thridparty api calls, and I want to mock all of them, while testing end to end flow, except thirdparty
This is what I have created -
Controller class
public class PortfolioController {
private final PortfolioService portfolioService;
}
Service Class
public class PortfolioService {
private final PortfolioTransactionRepository portfolioTransactionRepository;
private final AlphavantageService alphavantageService;
}
AlphaVantageService
public class AlphavantageService {
private ApiConfig apiConfig;
private final RestTemplate restTemplate;
public Map<String, List<Candle>> getStockQuotes(List<String> symbols) {
return symbols.stream().collect(Collectors.toMap(symbol -> symbol, symbol -> getQuotes(symbol)));
}
}
Now comes the test -
#ExtendWith(SpringExtension.class)
#WebMvcTest(controllers = PortfolioController.class)
class PortfolioControllerTest {
private List<PortfolioTransaction> transactions;
#MockBean
private AlphavantageService alphavantageService;
#MockBean
private PortfolioService portfolioService;
#Autowired
private PortfolioController portfolioController;
#Autowired
private MockMvc mockMvc;
}
The problem is, when I try to execute any mvc call on server, AlphaVantageService is not injected inside PortfolioService, so till level1, I get the beans injected, but on further levels, I dont get the same.
Is it by design or I am missing something? How should we test such test-cases?
Actually After trying some options here and there, I found a solution.
Just like #MockBean, spring also have a notion called #SpyBean. That solved my problem. So now my test looks like below
#ExtendWith(SpringExtension.class)
#WebMvcTest(controllers = PortfolioController.class)
#MockBeans(value = {#MockBean(AlphavantageService.class),
#MockBean(PortfolioTransactionRepository.class)})
#SpyBeans(value = {#SpyBean(PortfolioService.class)})
class PortfolioControllerTest {
private List<PortfolioTransaction> transactions;
#Autowired
private AlphavantageService alphavantageService;
#Autowired
#SpyBean
private PortfolioService portfolioService;
#Autowired
private PortfolioController portfolioController;
#Autowired
private MockMvc mockMvc;
}
This works like a charm and I can use full fledged dependency Injection in the tests.

Constructor Injection in configuration classes in Sprin5

I was trying to create a configuration class
#Configuration
public class AppConfig {
private final SomeBean someBean;
private final AnotherBean anotherBean;
#Autowired
public AppConfig(SomeBean someBean, AnotherBean anotherBean) {
this.someBean = someBean;
this.anotherBean = anotherBean;
}
}
Another approach with
#Configuration
public class AppConfig {
#Autowired
private final SomeBean someBean;
#Autowired
private final AnotherBean anotherBean;
}
Not sure which one I have to go for.
I have seen many codes with the second approach, but not with the first approach.
Any reason for this?

#Viewscope not working with #Scope(value=BeanDefinition.SCOPE_PROTOTYPE) in bean?

I have a controller which is annotated with
#Component(value = "somevalue")
#ViewScoped everything was working fine but i had a lazyModel class which was singleton so i annotated with #Scope(value=org.springframework.beans.factory.config.BeanDefinition.SCOPE_PROTOTYPE)
later i came to know #Autowire will give the same class for each request,so we need to get the class from context here is my controller...`#Component(value = "someValue")
#ViewScoped
public class ACAppUserController extends AbsController {
#Autowired
private SomeLazyModel lazyModel;
public SomeLazyModel getLazyModel() {
this.lazyModel = (SomeLazyModel) context.getBean("SomeLazyModel");
return lazyModel;
}
public void setLazyModel(ACAppUserLazyModel lazyModel) {
this.lazyModel = lazyModel;
}
}
And here is my SomeLazyModel which have userModel...
#Component(value = "SomeLazyModel")
#Scope(value=org.springframework.beans.factory.config.BeanDefinition.SCOPE_PROTOTYPE)
public class SomeLazyModel extends AbsSomeLazyModelLazyModel<UserModel> {
private static final long serialVersionUID = 1L;
private static final Logger logger = Logger
.getLogger(SomeLazyModel.class);
private UserModel user;
Usermodel is having username,password variables...
So my issue is When i submit the form username and password is null in
usermodel...
so before getting someLazyModel from context everything was working fine...
please do help on this...

Resources