I've been beating my head over this and I just can't figure out what's wrong.
I have a Spring app which uses ApplicationContext.getBean() to retrieve 2 similar classes. I'm getting the wrong instance class from the bean lookup.
Here's ApplicationContext class:
public class DomainRegistryCab {
private static ApplicationContext applicationContext;
private static ApplicationContext createApplicationContext() {
return new AnnotationConfigApplicationContext( CaBridgeDomainServiceConfig.class );
}
public static CertificateProductApplicationService certificateProductAppService() {
var service = BeanFactoryAnnotationUtils.qualifiedBeanOfType(
applicationContext().getAutowireCapableBeanFactory(),
CertificateProductApplicationService.class,
CaBridgeDomainServiceConfig.CERTIFICATE_PRODUCT_APP_SERVICE);
// var service = applicationContext().getBean(
// CaBridgeDomainServiceConfig.CERTIFICATE_PRODUCT_APP_SERVICE,
// CertificateProductApplicationService.class);
// var service = applicationContext().getBean(CertificateProductApplicationService.class);
validateDataSourceIs(DataSource.ProductDataStore, service.dataSource());
return service;
}
public static CertificateProgramApplicationService certificateProgramAppService() {
var service = BeanFactoryAnnotationUtils.qualifiedBeanOfType(
applicationContext().getAutowireCapableBeanFactory(),
CertificateProgramApplicationService.class,
CaBridgeDomainServiceConfig.CERTIFICATE_PROGRAM_APP_SERVICE);
// var service = applicationContext().getBean(
// CaBridgeDomainServiceConfig.CERTIFICATE_PROGRAM_APP_SERVICE,
// CertificateProgramApplicationService.class);
// service = applicationContext().getBean(CertificateProgramApplicationService.class);
validateDataSourceIs(DataSource.ProgramDataStore, service.dataSource());
return service;
}
Here is CaBridgeDomainServiceConfig:
#Configuration
#ComponentScan(basePackageClasses = { HibernateConfigurationMarker.class })
public class CaBridgeDomainServiceConfig {
public static final String CERTIFICATE_PRODUCT_APP_SERVICE = "certificateProductAppService";
public static final String CERTIFICATE_PROGRAM_APP_SERVICE = "certificateProgramAppService";
#Bean(name= CERTIFICATE_PRODUCT_APP_SERVICE)
public CertificateProductApplicationService certificateProductAppService() {
return new CertificateProductApplicationServiceCabImpl();
}
#Bean(name= CERTIFICATE_PROGRAM_APP_SERVICE)
public CertificateProgramApplicationService certificateProgramAppService() {
return new CertificateProgramApplicationServiceCabImpl();
}
}
public interface CertificateProductApplicationService extends CertificateApplicationService {
}
public interface CertificateProductApplicationService extends CertificateApplicationService {
}
public interface CertificateApplicationService {
}
Using the above classes if I call DomainRegistryCab.certificateProductAppService() I get an instance of CertificateProgramApplicationService not CertificateProductApplicationService.
I get similar results if I use this method:
public static CertificateProductApplicationService certificateProductAppService() {
var service = applicationContext().getBean(
CaBridgeDomainServiceConfig.CERTIFICATE_PRODUCT_APP_SERVICE,
CertificateProductApplicationService.class);
validateDataSourceIs(DataSource.ProductDataStore, service.dataSource());
return service;
}
I've also tried having the #Bean methods return the implementation classes and the ApplicationContext().getBean() to request the implementation classes instead of the interfaces:
public class DomainRegistryCab {
private static ApplicationContext applicationContext;
private static ApplicationContext createApplicationContext() {
return new AnnotationConfigApplicationContext( CaBridgeDomainServiceConfig.class );
}
public static CertificateProductApplicationService certificateProductAppService() {
var service = applicationContext().getBean(CertificateProductApplicationServiceCabImpl.class);
validateDataSourceIs(DataSource.ProductDataStore, service.dataSource());
return service;
}
public static CertificateProgramApplicationService certificateProgramAppService() {
var service = applicationContext().getBean(CertificateProgramApplicationServiceCabImpl.class);
validateDataSourceIs(DataSource.ProgramDataStore, service.dataSource());
return service;
}
public static ApplicationContext applicationContext() {
if (applicationContext == null)
applicationContext = createApplicationContext();
return applicationContext;
}
}
#ComponentScan(basePackageClasses = { HibernateConfigurationMarker.class })
public class CaBridgeDomainServiceConfig {
#Bean(name= CERTIFICATE_PRODUCT_APP_SERVICE)
public CertificateProductApplicationServiceCabImpl certificateProductAppService() {
return new CertificateProductApplicationServiceCabImpl();
}
#Bean(name= CERTIFICATE_PROGRAM_APP_SERVICE)
public CertificateProgramApplicationServiceCabImpl certificateProgramAppService() {
return new CertificateProgramApplicationServiceCabImpl();
}
}
This code results in spring not finding the implementation classes at all:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'cmb.cabridge.application.cert.CertificateProductApplicationServiceCabImpl' available
I was eventually able to get things to work using the applicationContext().getBean("beanName", CertificateProductApplicationService.class). The problem was deeper in my code in the CertificateProductApplicationServiceCabImpl class which used and returned the wrong datasource.
Related
I would like to create service which searching and returns objects from repositories, so:
I created interface which has method:
public interface ShapeServicesInterface {
List<ShapeEntity> getAll();
String getName();
}
and few services which implements that interface:
#Service
#RequiredArgsConstructor
public class CircleEntityService implements ShapeServicesInterface {
private final CircleEntityRepository circleEntityRepository;
#Override
public List<ShapeEntity> getAll() {
return new ArrayList<>(circleEntityRepository.findAll());
}
#Override
public String getName() {
return "circle";
}
}
and second one:
#Service
#RequiredArgsConstructor
public class SquareEntityService implements ShapeServicesInterface {
private final SquareEntityRepository squareEntityRepository;
#Override
public List<ShapeEntity> getAll() {
return new ArrayList<>(squareEntityRepository.findAll());
}
#Override
public String getName() {
return "square";
}
}
and next in other service I would like to call that method for getting all entites from that repositories (entites extend abstract class ShapeEntity) - found solution like that:
#Service
#RequiredArgsConstructor
public class TestService {
private final ShapeServiceFacade facade;
private final ExecutorService executorService;
public List<ShapeEntity> getAll() throws ExecutionException, InterruptedException {
List<ShapeEntity> allShapes = new ArrayList<>();
List<Future<List<ShapeEntity>>> futures = new ArrayList<>();
for (ShapeServicesInterface shapeDownloader : facade.getServices()) {
futures.add(executorService.submit(new ShapeTask(shapeDownloader)));
}
for (Future<List<ShapeEntity>> future : futures) {
allShapes.addAll(future.get());
}
return allShapes;
}
ShapeTask is:
#RequiredArgsConstructor
private static class ShapeTask implements Callable<List<ShapeEntity>> {
private final ShapeServicesInterface servicesInterface;
#Override
public List<ShapeEntity> call() {
return servicesInterface.getAll();
}
}
Facade is:
#Service
public class ShapeServiceFacade {
private final Map<String, ShapeServicesInterface> shapeServices;
public ShapeServiceFacade(Set<ShapeServicesInterface> allServices) {
this.shapeServices = allServices.stream()
.collect(Collectors.toMap(ShapeServicesInterface::getName,Function.identity()));
}
public List<ShapeServicesInterface> getServices() {
return new ArrayList<>(shapeServices.values());
}
}
but it is a little complicated. Is there a easier way to call that methods? I would like to add more methods so I will have to implement another task and another method in service, and in interface. I care about searching in every repostiory.
Maybe the ShapeServiceFacade can be omitted, if you are using spring boot, like that
#Service
#RequiredArgsConstructor
public class TestService {
#Autowired
private final List<ShapeServicesInterface> serviceList;
private final ExecutorService executorService;
public List<ShapeEntity> getAll() throws ExecutionException, InterruptedException {
List<ShapeEntity> allShapes = new ArrayList<>();
List<Future<List<ShapeEntity>>> futures = new ArrayList<>();
for (ShapeServicesInterface shapeDownloader : serviceList) {
futures.add(executorService.submit(new ShapeTask(shapeDownloader)));
}
for (Future<List<ShapeEntity>> future : futures) {
allShapes.addAll(future.get());
}
return allShapes;
}
I have a class annotated with #Component which is use to initialze application.yml config properties. Service classe is using configuration property. But sometime my Service class instance created before the Configuration class and I get null property value in service class, Its random not specific pattern.
Configuration Initializer class..
#Component
public class ConfigInitializer implements InitializingBean {
private static final Logger log = LoggerFactory.getLogger(ConfigInitializer.class);
#Autowired
ProxyConfig proxyConfig;
/*#PostConstruct
public void postConstruct(){
setProperties();
}
*/
#Override
public void afterPropertiesSet() {
setProperties();
}
private void setSystemProperties(){
log.debug("Setting properties...");
Properties props = new Properties();
props.put("PROXY_URL", proxyConfig.getProxyUrl());
props.put("PROXY_PORT", proxyConfig.getProxyPort());
System.getProperties().putAll(props);
}
}
#Component
#ConfigurationProperties(prefix = "proxy-config")
public static class ProxyConfig {
private String proxyUrl;
private String proxyPort;
public String getProxyUrl() {
return proxyUrl;
}
public void setProxyUrl(String proxyUrl) {
this.proxyUrl = proxyUrl;
}
public String getProxyPort() {
return proxyPort;
}
public void setProxyPort(String proxyPort) {
this.proxyPort = proxyPort;
}
}
Service Class..
#Service("receiverService")
public class ReceiverService {
private static final Logger logger = LoggerFactory.getLogger(ReceiverService.class);
private ExecutorService executorService = Executors.newSingleThreadExecutor();
#Autowired
public ReceiverService() {
initClient();
}
private void initClient() {
Future future = executorService.submit(new Callable(){
public Object call() throws Exception {
String value = System.getProperty("PROXY_URL"); **//Here I am getting null**
logger.info("Values : " + value);
}
});
System.out.println("future.get() = " + future.get());
}
}
Above Service class get null values String value = System.getProperty("PROXY_URL")
When I use #DependsOn annotation on Service class, it works fine.
In my little knowledge, I know Spring does not have specific order of bean creation.
I want to know If I use #Configuration instead of #Component on ConfigInitializer class like below, Will spring initialize ConfigInitializer
class before other beans ?.
#Configuration
public class ConfigInitializer implements InitializingBean {
//code here
}
The example I tried to follow:
#PrepareForTest(X.class)
public class XTest extends PowerMockTestCase {
#Test
public void test() {
whenNew(MyClass.class).withNoArguments().thenThrow(new IOException("error message"));
X x = new X();
x.y(); // y is the method doing "new MyClass()"
..
}
}
The factory class I am trying to unit test:
public final class LoadableBeanFactory implements ILoadableBeanFactory {
private static final class Loader {
private static final LoadableBeanFactory INSTANCE = new LoadableBeanFactory();
}
private LoadableBeanFactory() { }
public static #Nonnull LoadableBeanFactory getInstance() {
return Loader.INSTANCE;
}
public final #Nonnull <BeanT extends ILoadableBean> BeanT create(final Class<BeanT> beanClass) {
final BeanT optionBean;
try {
final Constructor<BeanT> ctor = beanClass.getConstructor();
optionBean = ctor.newInstance();
return beanClass.cast(optionBean);
} catch(Exception e) {
throw new IllegalArgumentException("Could not instantiate an instance of " + beanClass);
}
}
}
My test is below. The factory does not return the mock. I am thinking that this is because the factory is a singleton that is instantiated and loaded with a private static loader class. So, is there a way to mock this object creation scenario or should I just give up on making this into a true unit test?
#PrepareForTest(LoadableBeanFactory.class)
#Test(groups = {"FactoryTestGroup", "LoadableBeanFactoryTestGroup"})
public class LoadableBeanFactoryTest extends PowerMockTestCase {
#Mock LoadableBean mockBean;
public void setUp() {
MockitoAnnotations.initMocks(this);
}
#Test
public void shouldCreateBean() {
try {
PowerMockito.whenNew(LoadableBean.class).withNoArguments().thenReturn(mockBean);
LoadableBeanFactory.getInstance().create(LoadableBean.class);
assertEquals(LoadableBeanFactory.getInstance().create(LoadableBean.class), mockBean,
"LoadableBeanFactory should have return mocked bean, but did not: " + mockBean);
} catch(Exception e) {
fail("Failed to mock bean creation");
}
}
}
Why would you even want to do that?
If you wrap the factory in an abstraction (a separate class) then you can inject it via constructor and mock its create method.
public class BeanFactory {
public <BeanT extends ILoadableBean> BeanT create(final Class<BeanT> beanClass) {
return LoadableBeanFactory.getInstance().create(beanClass);
}
}
and now your class that you want to work with
public class SomeClass {
private final BeanFactory beanFactory;
public SomeClass(BeanFactory beanFactory) {
this.beanFactory= beanFactory;
}
public void doSth() {
beanFactory.create(...);
}
}
And then you don't need to have PowerMock at all and your design is really nice.
I'm using the Spring Akka example posted on activator to create Spring managed bean actors. This is the code I'm currently using including a demo class:
#Component
class Test extends UntypedActor {
#Autowired
protected ObjectMapper objectMapper;
protected final Account account;
protected final Order order;
public Test(Account account, Order order) {
this.account = account;
this.order = order;
}
#Override
public void onReceive(Object message) throws Exception {
if (message instanceof SomeCommand) {
// Do something using the order and the account;
} else if (message instanceof FooCommand) {
// More stuff
}
}
}
#Component
public class SpringExtension extends AbstractExtensionId<SpringExtensionImpl> implements ExtensionIdProvider {
#Autowired
private ApplicationContext applicationContext;
#Override
public SpringExtensionImpl createExtension(ExtendedActorSystem system) {
return applicationContext.getBean(SpringExtensionImpl.class);
}
#Override
public ExtensionId<? extends Extension> lookup() {
return applicationContext.getBean(SpringExtension.class);
}
}
#Component
public class SpringExtensionImpl implements Extension {
#Autowired
private ApplicationContext applicationContext;
public Props props(String actorBeanName) {
return Props.create(SpringActorProducer.class, applicationContext, actorBeanName);
}
}
public class SpringActorProducer implements IndirectActorProducer {
private final ApplicationContext applicationContext;
private final String actorBeanName;
public SpringActorProducer(ApplicationContext applicationContext, String actorBeanName) {
this.applicationContext = applicationContext;
this.actorBeanName = actorBeanName;
}
#Override
public Actor produce() {
return (Actor) applicationContext.getBean(actorBeanName);
}
#Override
public Class<? extends Actor> actorClass() {
return (Class<? extends Actor>) applicationContext.getType(actorBeanName);
}
}
Now my question is, how do instantiate an actor with custom constructor arguments. I have thought about using a factory or setter methods but I don't think this is an option since the underlying Actor class is not accessible I believe. Any input on this matter is greatly appreciated. If something is now clear, please post a comment.
PS. If you believe my there is an error in my code or there is a better way of going about it, please do tell me! I have little experience with Spring and Akka combined so any advice is appreciated.
You could pass the additional arguments as varargs (Object...) to SpringExtensionImpl and SpringActorProducer. So your code would look like this:
#Component
public class SpringExtensionImpl implements Extension {
#Autowired
private ApplicationContext applicationContext;
public Props props(String actorBeanName, Object... args) {
return (args != null && args.length > 0) ?
Props.create(SpringActorProducer.class,
applicationContext,
actorBeanName, args) :
Props.create(SpringActorProducer.class,
applicationContext,
actorBeanName);
}
}
public class SpringActorProducer implements IndirectActorProducer {
private final ApplicationContext applicationContext;
private final String actorBeanName;
private final Object[] args;
public SpringActorProducer(ApplicationContext applicationContext, String actorBeanName) {
this.applicationContext = applicationContext;
this.actorBeanName = actorBeanName;
this.args = null;
}
public SpringActorProducer(ApplicationContext applicationContext, String actorBeanName, Object... args) {
this.applicationContext = applicationContext;
this.actorBeanName = actorBeanName;
this.args = args;
}
#Override
public Actor produce() {
return args == null ?
(Actor) applicationContext.getBean(actorBeanName):
(Actor) applicationContext.getBean(actorBeanName, args);
}
#Override
public Class<? extends Actor> actorClass() {
return (Class<? extends Actor>) applicationContext.getType(actorBeanName);
}
}
You can then create your Test actor like this:
SpringExtensionImpl springExtensionImpl;
actorSystem.actorOf(springExtensionImpl.create(Test.class, account, order));
I have a little problem. I think this is typical question. However, I can't find good example. My application is using Jersey. And I want to test controller by client as test. Controller has private field - StudentService. When I debug test I see, that field is null. This leads to error. And I need to inject this field. I tried this:
My Controller
#Path("/student")
#Component
public class StudentResourse {
#Autowired
private StrudentService service; // this field Spring does not set
#Path("/getStudent/{id}")
#GET
#Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public Student getStudent(#PathParam("id") long id) {
return service.get(id);
}
}
My JUnit test class:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = "classpath:config.xml")
#TestExecutionListeners({ DbUnitTestExecutionListener.class,
DependencyInjectionTestExecutionListener.class,
DirtiesContextTestExecutionListener.class,
TransactionalTestExecutionListener.class })
public class StudentResourseTest extends JerseyTest {
private static final String PACKAGE_NAME = "com.example.servlet";
private static final String FILE_DATASET = "/data.xml";
#Autowired
private StudentService service; // this field is setted by Spring, but I do not need this field for test
public StudentResourseTest() {
super(new WebAppDescriptor.Builder(PACKAGE_NAME).build());
}
#Override
protected TestContainerFactory getTestContainerFactory() {
return new HTTPContainerFactory();
}
#Override
protected AppDescriptor configure() {
return new WebAppDescriptor.Builder("restful.server.resource")
.contextParam("contextConfigLocation",
"classpath:/config.xml").contextPath("/")
.servletClass(SpringServlet.class)
.contextListenerClass(ContextLoaderListener.class)
.requestListenerClass(RequestContextListener.class).build();
}
#Test
#DatabaseSetup(FILE_DATASET)
public void test() throws UnsupportedEncodingException {
ClientResponse response = resource().path("student").path("getStudent")
.path("100500").accept(MediaType.APPLICATION_XML)
.get(ClientResponse.class);
Student student = (Student) response.getEntity(Student.class);
} }
I guees, that problem is in test class. Because, when I run my application not in test, I can directly request students and everything working fine. But when I test classes, internal field of Controller does not setted. How to fix this bug? Thanks for your answers.
This is in my config.xml
<context:component-scan base-package="com.example" />
<bean id="StudentResourse" class="com.example.servlet.StudentResourse">
<property name="service" ref="studentService" />
</bean>
<bean id="service" class="com.example.service.StudentServiceImpl" />
One issue may be that you're trying to configure your test application in constructor and in configure() method. Use one or another but not both because in this case your configure() method is not invoked and hence you may not be using SpringServlet and everything that is defined in this method.
Reference: https://github.com/jiunjiunma/spring-jersey-test and http://geek.riffpie.com/unit-testing-restful-jersey-services-glued-together-with-spring/
Idea is to get a hold of the application context inside jersey by using ApplicationContextAware interface. There after we can grab the exact bean already created by spring, in your case, StudentService. Below example shows a mocked version of the dependency, SampleService, used to test the resource layer apis.
Resource class delegating the processing to a service layer
#Component
#Path("/sample")
public class SampleResource {
#Autowired
private SampleService sampleService;
#GET
#Produces(MediaType.APPLICATION_JSON)
#Path ("/{id}")
public Sample getSample(#PathParam("id") int id) {
Sample sample = sampleService.getSample(id);
if (sample == null) {
throw new WebApplicationException(Response.Status.NOT_FOUND);
}
return sample;
}
}
Service layer encapsulating business logic
#Service
public class SampleService {
private static final Map<Integer, Sample> samples = new HashMap<>();
static {
samples.put(1, new Sample(1, "sample1"));
samples.put(2, new Sample(2, "sample2"));
}
public Sample getSample(int id) {
return samples.get(id);
}
}
Unit test for the above resource
public class SampleResourceTest extends SpringContextAwareJerseyTest {
private SampleService mockSampleService;
// create mock object for our test
#Bean
static public SampleService sampleService() {
return Mockito.mock(SampleService.class);
}
/**
* Create our own resource here so only the test resource is loaded. If
* we use #ComponentScan, the whole package will be scanned and more
* resources may be loaded (which is usually NOT what we want in a test).
*/
#Bean
static public SampleResource sampleResource() {
return new SampleResource();
}
// get the mock objects from the internal servlet context, because
// the app context may get recreated for each test so we have to set
// it before each run
#Before
public void setupMocks() {
mockSampleService = getContext().getBean(SampleService.class);
}
#Test
public void testMock() {
Assert.assertNotNull(mockSampleService);
}
#Test
public void testGetSample() {
// see how the mock object hijack the sample service, now id 3 is valid
Sample sample3 = new Sample(3, "sample3");
Mockito.when(mockSampleService.getSample(3)).thenReturn(sample3);
expect().statusCode(200).get(SERVLET_PATH + "/sample/3");
String jsonStr = get(SERVLET_PATH + "/sample/3").asString();
Assert.assertNotNull(jsonStr);
}
}
SpringContextAwareJerseyTest
#Configuration
public class SpringContextAwareJerseyTest extends JerseyTest {
protected static String SERVLET_PATH = "/api";
final private static ThreadLocal<ApplicationContext> context =
new ThreadLocal<>();
protected String getResourceLocation() {
return "example.rest";
}
protected String getContextConfigLocation() {
return getClass().getName();
}
static private String getContextHolderConfigLocation() {
return SpringContextAwareJerseyTest.class.getName();
}
protected WebAppDescriptor configure() {
String contextConfigLocation = getContextConfigLocation() + " " +
getContextHolderConfigLocation();
Map<String, String> initParams = new HashMap<>();
initParams.put("com.sun.jersey.config.property.packages",
getResourceLocation());
initParams.put("com.sun.jersey.api.json.POJOMappingFeature", "true");
return new WebAppDescriptor.Builder(initParams)
.servletClass(SpringServlet.class)
.contextParam(
"contextClass",
"org.springframework.web.context.support.AnnotationConfigWebApplicationContext")
.contextParam("contextConfigLocation", contextConfigLocation)
.servletPath(SERVLET_PATH) // if not specified, it set to root resource
.contextListenerClass(ContextLoaderListener.class)
.requestListenerClass(RequestContextListener.class)
.build();
}
protected final ApplicationContext getContext() {
return context.get();
}
#Bean
public static ContextHolder contextHolder() {
return new ContextHolder();
}
private static class ContextHolder implements ApplicationContextAware {
#Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
context.set(applicationContext);
}
}
}
Using the above with jersey 1.8