Quarkus, profile at bean / class level - quarkus

I would like to initialize the class based on the profile. I have mock service for development and prod has real implementation.
public interface Service {
}
For dev:
//#Profile("Dev") -- not supported in quarkus
#ApplicationScoped
public MockService implements Service {
}
For Prod
//#Profile("prod") -- not supported in quarkus
#ApplicationScoped
public MainService implements Service {
}
Is it possible with quarkus? is there any work around?

Check out this part of the documentation.
Your example would likely look like:
#IfBuildProfile("dev")
#ApplicationScoped
public MockService implements Service {
}
#DefaultBean
#ApplicationScoped
public MainService implements Service {
}

Related

Springboot #Transactional - How to make spring call super when it creates service proxy?

I have intermediate skills in Springboot and can develop simple to medium complex applications but this one is throwing me off a little bit.
I have a #Service that extends Guava's AbstractIdleService and a #Controller that has instance of the service autowired.
In the service, I have a method, say performTransaction() that is annotated with #Transactional (ofcourse to let Spring take care of transactions) and it does create a proxy of the service class. But when I debug the application I can see that the proxy that is injected in the controller contains all super class (AbstractIdleService) class fields as null meaning super() is not called when the proxy of my service was created. Because of this the application is failing to initialize when calling the super class's (AbstractIdleService) startAsync method. I am not really sure how to make this work.
I have added some code below for illustration.
This is my service class:
import com.google.common.util.concurrent.AbstractIdleService;
import org.springframework.transaction.annotation.Transactional;
#Service
public class MyService extends AbstractIdleService {
#Transactional
public void performTransaction() {
}
}
This is the controller that uses the above service:
#Controller
public void MyController {
private MyService service;
private EurekaRegistration eurekaRegistration;
#Autowired
public MyController(MyService service, EurekaRegistration eurekaRegistration) {
this.service = service; // This is where the proxy contains all AbstractIdleService fields null
this.eurekaRegistration = eurekaRegistration;
}
#EventListener({ ApplicationPreparedEvent.class })
public void handleApplicationPreparedEvent() {
this.service.startAsync(); // This line throws NPE, as delegate in the parent is null
this.service.awaitRunning();
}
}
I must use AbstractIdleService as that is the organizational convention and I need to invoke some startup code in the startAsync method. But invoking startAsync method on the service is causing a NullPointerException as it uses a parent field that is null because the proxy initialization never called super.
I'm not 100% sure if this is the actual problem, but try something like this (untested):
Interface for proxy:
import com.google.common.util.concurrent.Service;
public interface MyService extends Service {
void performTransaction();
}
Implementation:
import com.google.common.util.concurrent.AbstractIdleService;
import org.springframework.transaction.annotation.Transactional;
#Service
public class MyServiceImpl extends AbstractIdleService implements MyService {
#Transactional
public void performTransaction() {
}
}
Controller, declare service interface, not implementation:
#Controller
public void MyController {
private MyService service;
private EurekaRegistration eurekaRegistration;
#Autowired
public MyControlle(MyService service, EurekaRegistration eurekaRegistration) {
this.service = service;
this.eurekaRegistration = eurekaRegistration;
}
}

Spring boot #Inject proxy resolves to null

I'm refactoring an existing application to use Spring Boot. The issues I've faced here are generally of the type "why is this not working anymore".
I have three packages
- nl.myproject.boot
- nl.myproject
- nl.myproject.rest
My current problem is that all #Services that I #Inject in a #RESTController resolve to null when a method is called on them.
The service and dao are part of the nl.myproject package and the reason it's not nl.myproject.core is a legacy issue.
A related issue is that my #Configuration components don't seem to be loaded through #ComponentScan and I have to import them manually. I also had to exclude Test configuration to prevent Test configs from being loaded, which also seemed weird.
Internal calls from the service layer during start up, such as data preparation works normally. Any such manager is also #Injected. This is just to say that any of the typical injection mistakes such as manual instantiation or injecting a class instead of an interface don't apply.
I'd also be grateful for debugging tips. My Java has gotten a little rusty.
#EnableAutoConfiguration
#ComponentScan(basePackages= {
"nl.myproject",
"nl.myproject.boot",
"nl.myproject.dao",
"nl.myproject.service",
"nl.myproject.webapp"},
excludeFilters= {
#ComponentScan.Filter(type=FilterType.REGEX,pattern={".*Test.*"}),
#ComponentScan.Filter(type=FilterType.REGEX,pattern={".*AppConfig"})
}
)
#Configuration
#EnableConfigurationProperties
#Import({
JPAConfig.class,
RestConfig.class,
BootConfig.class
})
public class Startup {
public static void main(String[] args) throws Exception {
SpringApplication.run(Startup.class, args);
}
}
#RestController
#RequestMapping(value="/json/tags")
public class JsonTagController extends JsonBaseController {
#Inject
TagManager tagMgr;
public interface TagManager extends BaseManager<Tag,Long> {
[...]
}
#Service("tagManager")
public class TagManagerImpl extends BaseManagerImpl<Tag, Long> implements
TagManager {
#Inject
TagDao dao;
[...]
#Inject is a annotation specified by JSR-330 (standard) whereas #Autowired is annotation specified by Spring.
They just do the same dependency injection. You can both of them in the same code.
Just the modification (separation of the concerns) you need :
public interface TagManager {
[...]
}
#Service
public class TagManagerImpl implements TagManager {
#Inject
private TagDao dao;
// inject that service rather than extending
#Inject
private BaseManager<Tag,Long> baseManager;
}
public interface BaseManager<Tag,Long> {
[...]
}
#Service
public class BaseManagerImpl<Tag,Long> implements BaseManager<Tag,Long> {
....
}
Just one thing you do for checking, just modify to basePackages= {"nl.myproject"} - just provide only base package, that's enough for spring to scan the components in every package.
Hope this may help :)

Using #SpringApplicationConfiguration annotation to injecting mocks into a Spring bean

There is the spring-boot application that uses spring-aop. proxy-target-class is true.
I'm trying to create a test for a service class. This service depends on a component class. I want to inject a mock into the service instead of the real component.
I found some similar questions:
Mocking a property of a CGLIB proxied service not working
Injecting Mockito mocks into a Spring bean
I choose this answer to the last question, and I have tried to implement this approach. I chose it because it is not tied to the implementation details of the proxy classes and I can easily use a config class in other tests.
Below there is the example which simulates the real problem.
#org.aspectj.lang.annotation.Aspect
#org.springframework.stereotype.Component
public class Aspect {
#Before("within(demo.Service)")
public void someAdvice() {
System.out.println("advice");
}
}
#org.springframework.stereotype.Service
public class Service {
#Autowired
private Component component;
public void action() {
System.out.println(component.action());
}
}
#org.springframework.stereotype.Component
public class Component {
public String action() {
return "real action";
}
}
#SpringApplicationConfiguration
public class ServiceTest extends BaseTest {
#Autowired
Service service;
#Test
public void testAction() {
service.action();
}
#Configuration
public static class Config {
#Mock Component mock;
public Config() {
MockitoAnnotations.initMocks(this);
}
#Bean
public Component component() {
Mockito.when(mock.action()).thenReturn("mock action");
return mock;
}
}
}
Complete example: https://github.com/eds0404/spring-inject-mock-into-proxy
The above code is not working as I expect, the service does not use mock ("real action" will be printed if you run test). But the above code works fine if the Component class is not marked with #Component annotation, and its objects are created by the method with #Been annotation.
How to solve this issue? If this is wrong approach, what is best practice?

Mocking a service within service (JUnit)

I have the following service:
#Service
public class PlayerValidationService {
#Autowire
private EmailService emailService;
public boolean validatePlayerEmail(Player player) {
return this.emailService.validateEmail(player.getEmail());
}
Now in my junit test class i'm using a different 3rd service that uses PlayerValidationService :
public class junit {
#autowire PlayerAccountService playerAccountService ;
#Test
public test() {
this.playerAccountService .createAccount();
assertAllSortsOfThings();
}
Is it possible to mock the EmailService within the PlayerAccountService when using annotation based autowiring? (for example make the mock not checking the validation of the email via the regular email provider we work with)
thanks.
There are a couple of ways in which you could do this. First the simplest option is to ensure that your service provides a setEmailService(EmailService) method. In which case you just replace the Spring-injected implementation with your own.
#Autowired
private PlayerValidationService playerValidationService;
#Mock
private EmailService emailService;
#Before
public void setup() {
initMocks(this);
playerValidationService.setEmailService(emailService);
}
A shortcoming of that approach is that an instance of the full-blown EmailService is likely to be created by Spring. Assuming that you don't want that to happen, you can use 'profiles'.
In your test packages, create a configuration class which is only active in a particular profile:
#Configuration
#Profile("mockemail")
public class MockEmailConfig {
#Bean(name = "emailService")
public EmailService emailService() {
return new MyDummyEmailService();
}
}
And add an annotation to your test to activate that profile:
#ActiveProfiles({ "mockemail" })
public class PlayerValidationServiceTest {
//...
}

Spring injection of Service within another Service

I have two Services and a Controller that I am trying to set up, like this:
Controller class:
#Controller
public class MyController {
#Autowired
IMyService1 service;
}
Service 2:
#Service
public class MyService2 implements IMyService2 { }
Service 1:
#Service
public class MyService1 implements IMyService1 {
#Autowired
IMyService2 myService2; // this bean is not getting created
}
Everything is set up correctly in beans.xml to pick up the Components in the component scan, and everything is under the same base package.
The first service is properly injected into the Controller class, but the second service is failing to be injected (BeanCreationException) into the first Service.
Has anyone run into this or any ideas/suggestions on what I may be doing wrong here?
I did some research on the subject, but I couldn't find an answer that solved this problem and I was only able instantiating the second service dynamically without #Service annotation.
Controller: Don't touch, it's the same
#Controller
public class MyController {
#Autowired
IMyService1 service;
}
Service 2: Remove #Service from the second service
public class MyService2 implements IMyService2 {
public void doSomething() {
// your code
}
}
Service 1: Remove #Autowired and dynamically instantiate your second service
#Service
public class MyService1 implements IMyService1 {
public void actionWithService2() {
new MyService2().doSomething();
}
}

Resources