I am currently fronting issues mixing a CXF web service with Spring #Configurable annotation.
From one side I have my CXF web service fully working and configured like this :
<import resource="classpath:some-other-context.xml" />
<jaxws:server id="Init"
serviceClass="package.to.my.ServiceInterface"
address="/">
<jaxws:serviceBean>
<bean class="package.to.my.BADematInitImpl">
</bean>
</jaxws:serviceBean>
</jaxws:server>
<context:spring-configured />
And in my some-other-context.xml is my Spring configuration containing the following Bean's :
#Configurable(autowire = Autowire.BY_TYPE)
public class MyConfigurable {
#Autowired(required=true)
private A a;
#Autowired(required=true)
private B b;
#Autowired(required=true)
private C c;
...
}
But when I try to create a new instance of MyConfigurable bean into my service, I get a NullPointerException due to the null valued supposed-autowired A,B and C objects.
Any idea ?
#Configurable is a marker used by the AOP load-time-weaving stuff. I assume you are not using any AOP, because there is nothing mentioned about it in your question. Second thing: you don't have to use required=true in your #Autowired annotation as true is the default value of required. I would suggest you to change your code like this:
Add these to elements in your spring configuration file:
<context:component-scan base-package="your.pckg.toscan"/>
Documentation says:
Scans the classpath for annotated components that will be
auto-registered as Spring beans. By default, the Spring-provided
#Component, #Repository, #Service, and #Controller stereotypes will
be detected.
<context:annotation-config/>
Documentation says:
Activates various annotations to be detected in bean classes: Spring's
#Required and #Autowired, as well as JSR 250's #PostConstruct,
#PreDestroy and #Resource (if available), JAX-WS's #WebServiceRef (if
available), EJB3's #EJB (if available), and JPA's #PersistenceContext
and #PersistenceUnit (if available). Alternatively, you may choose to
activate the individual BeanPostProcessors for those annotations.
So changing your code to:
#Component
public class MyConfigurable {
#Autowired
private A a;
#Autowired
private B b;
#Autowired
private C c;
...
}
Everything should work just fine.
I finally found out the problem.
I needed to add this configuration into my third-part application XML files :
<context:load-time-weaver/>
... and add this argument to my jvm launch command line :
-javaagent:"path\to\my\spring-agent.jar"
And it just works like a charm.
I understand that this is because Spring needs at some point to have an entity managing its AOP part so that the dependencies are well injected. It would be interesting if someone had further explanations.
Related
I'm attempting to set up some Spring Boot JPA tests using:
package biz.ianw.coindatabase.test;
#RunWith(SpringRunner.class)
#DataJpaTest
public class DbTests {
#Test
public void test1() { ... }
}
I have a service class:
package biz.ianw.coindatabase.database;
//#Service
#Repository
#Transactional(readOnly=false)
public class CoinDbService { ... }
and an application:
package biz.ianw.coindatabase;
#SpringBootApplication
#Slf4j
#Configuration
#EnableEncryptableProperties
public class Main {
#Autowired
CoinDbService dbService;
... }
Starting the test gives the error:
Field dbService in biz.ianw.coindatabase.Main required a bean of type 'biz.ianw.coindatabase.database.CoinDbService' that could not be found.
This is, I assumed, something to do with the type of beans #DataJpaTest loads during startup:
#DataJpaTest can be used if you want to test JPA applications. By
default it will configure an in-memory embedded database, scan for
#Entity classes and configure Spring Data JPA repositories. Regular
#Component beans will not be loaded into the ApplicationContext.
I'm not quite sure why #Service classes should be considered as not required for JPA testing, but I tried to force the matter by annotating it as #Repository instead, but to no avail.
I can manually load the class with #Import(...) but it seems a tad hooky. Is there a better way to tell DataJpaTest what I need for testing?
I am quoting from DataJpaTest documentation where you can find the answer to your question.
Annotation that can be used in combination with
#RunWith(SpringRunner.class) for a typical JPA test. Can be used when
a test focuses only on JPA components.
Using this annotation will disable full auto-configuration and instead
apply only configuration relevant to JPA tests.
By default, tests annotated with #DataJpaTest will use an embedded
in-memory database (replacing any explicit or usually auto-configured
DataSource). The #AutoConfigureTestDatabase annotation can be used to
override these settings.
If you are looking to load your full application configuration, but
use an embedded database, you should consider #SpringBootTest combined
with #AutoConfigureTestDatabase rather than this annotation.
I'm porting an app across from JDBC / REST to spring-data-rest and my one and only unit test with fails with the error
NoSuchBeanDefinitionException:
No qualifying bean of type 'com.xxx.repository.ForecastRepository' available
The app was retro-fitted with spring-boot just previously, and now I'm trying to put a new layer in place with spring-data-rest on top of spring-data-jpa.
I'm attempting to work out the correct Java-config according to
Custom Test Slice with Spring Boot 1.4
but I had to deviate from the idiomatic approach because
the #WebMvcTest annotation doesn't suppress the security module which causes the test to fail
the #MockMvcAutoConfiguration fails due to missing dependencies unless I specify #SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK) (see here)
#WebMvcTest and #SpringBootTest are mutually exclusive since they both specify #BootstrapWith and can't run together
So this is the closest I've got but Spring can't locate my #RepositoryRestResource repository:
Repository
#RepositoryRestResource(collectionResourceRel = "forecasts", path = "forecasts")
public interface ForecastRepository extends CrudRepository<ForecastExEncoded,
Long> {
JUnit Test
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK,
classes = {TestRestConfiguration.class})
public class ForecastRestTests {
#Autowired
private MockMvc mockMvc;
#Autowired
private ForecastRepository forecastRepository;
#Before
public void deleteAllBeforeTests() throws Exception {
forecastRepository.deleteAll();
}
#Test
public void shouldReturnRepositoryIndex() throws Exception {
mockMvc.perform(get("/")).andDo(print()).andExpect(status().isOk()).andExpect(
jsonPath("$._links.forecasts").exists());
}
}
Configuration
#OverrideAutoConfiguration(enabled = false)
#ImportAutoConfiguration(value = {
RepositoryRestMvcAutoConfiguration.class,
HttpMessageConvertersAutoConfiguration.class,
WebMvcAutoConfiguration.class,
MockMvcAutoConfiguration.class,
MockMvcSecurityAutoConfiguration.class
})
#Import({PropertySpringConfig.class})
public class TestRestConfiguration {}
Also tried...
I tried to configure the unit test with just #WebMvcTest and this #ComponentScan below from How to exclude AutoConfiguration from Spring Boot), in an attempt to simplify it all, however the excludeFilters had no effect.
#ComponentScan(
basePackages="com.xxx",
excludeFilters = {
#ComponentScan.Filter(type = ASSIGNABLE_TYPE,
value = {
SpringBootWebApplication.class,
JpaDataConfiguration.class,
SecurityConfig.class
})
})
I've set Spring's logging to trace because all I can do at this point is try to find clues as to what is happening from log output. So far though without any luck.
I can see in the logging that RepositoryRestConfiguration is loading, but obviously it isn't fed with the right info and I am unable to work out how that is done, after googling and pouring over the Spring docs and API. I think I must have read every relevant question here on SO .
Update 2016-11-16 10:00
One thing I see in the logs which concerns me is this:
Performing dependency injection for test context [DefaultTestContext#2b4a2ec7 [snip...]
classes = '{class com.xxx.TestRestConfiguration,
class com.xxx.TestRestConfiguration}',
i.e. the context lists the configuration class twice. I specified the config class (once only) on the #SpringBootTest#classes annotation. But if I leave off the #classes from the annotation, Spring Boot finds and pulls in all the config via the #SpringBootApplication class.
So is that a hint that I am specifying the configuration in the wrong place? How else would I do it?
After way too much time, I settled on this approach.
Custom Test Slice with Spring Boot 1.4 looked promising but I couldn't get anywhere with it.
While going over and over
Accessing JPA Data with REST
I realised I had to include the JPA setup because spring-data-rest is using them directly - no chance to mock them or run unit tests without an embedded database.
At least not as far as I understand it. Maybe it is possible to mock them and have spring-data-rest run on the mocks against test data, but I think spring-data-rest and spring-data are probably too tightly coupled.
So integration testing it must be.
In the Spring source code provided with the articles above
gs-accessing-data-rest/ApplicationTests.java
the logging shows Spring Boot pulling in the whole configuration for the application context.
So that my SpringBootApplication class is avoided and the security module isn't loaded up, I set up my tests like this:
#RunWith(SpringRunner.class)
#SpringBootTest
#ContextConfiguration(classes = {
JpaDataConfiguration.class,
TestJpaConfiguration.class,
TestRestConfiguration.class,
PropertySpringConfig.class})
public class ForecastRestTests {
#SuppressWarnings("SpringJavaAutowiringInspection")
#Autowired
private MockMvc mockMvc;
#Autowired
private ForecastRepository forecastRepository;
#Before
public void deleteAllBeforeTests() throws Exception {
forecastRepository.deleteAll();
}
#Test
public void shouldReturnRepositoryIndex() throws Exception {
mockMvc.perform(get("/")).andDo(print()).andExpect(status().isOk()).andExpect(
jsonPath("$._links.forecasts").exists());
}
}
with these configuration classes:
#Configuration
#EnableJpaRepositories(basePackages = {"com.bp.gis.tardis.repository"})
#EntityScan(basePackages = {"com.bp.gis.tardis.type"})
public class JpaDataConfiguration {
and
#Configuration
#OverrideAutoConfiguration(enabled = false)
#ImportAutoConfiguration(value = {
CacheAutoConfiguration.class,
JpaRepositoriesAutoConfiguration.class,
DataSourceAutoConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class,
HibernateJpaAutoConfiguration.class,
TransactionAutoConfiguration.class,
TestDatabaseAutoConfiguration.class,
TestEntityManagerAutoConfiguration.class })
public class TestJpaConfiguration {}
and
#Configuration
#OverrideAutoConfiguration(enabled = false)
#ImportAutoConfiguration(value = {
RepositoryRestMvcAutoConfiguration.class,
HttpMessageConvertersAutoConfiguration.class,
WebMvcAutoConfiguration.class,
MockMvcAutoConfiguration.class,
MockMvcSecurityAutoConfiguration.class
})
public class TestRestConfiguration {}
so the TL;DR summary is: use #ContextConfiguration to specify the configuration files that specify #OverrideAutoConfiguration and #ImportAutoConfiguration
How would you go about integration testing a spring application that is annotation-configured and component-scanned and does not have an XML configuration at all? I'm hitting a wall with the need to replace production components with testing components without actually resorting to xml configuration or reflection injections to all the #autowired parts.
Example:
interface A {...}
#Component
class AImpl implements A {
...
}
interface B {...}
#Component
class BImpl implements B {
#Autowired A a;
...
}
interface C {...}
class CImpl implements C {
#Autowired B b;
...
}
then in my test I want to use ATestImpl, but I only have access to C (integration testing C).
How would you go about doing that?
Take advantage of #Primary annotation:
#Service
#Primary
public class TestA implements A {
//...
}
If there is more than one bean implementing A, Spring will prefer the one annotated with #Primary. If you place TestA class in /src/test/java, it will only be picked up during test execution, on normal context startup Spring won't see TestA and use only avaialble AImpl.
Use a dedicated spring context XML file where you override AImpl with an instance of ATestImpl. Of course, it uses XML, but I don't see any other solution (other than repackaging the application with your ATestImpl annotated class instead of the AImpl one)
The new Bean Profile features in Spring 3.1 address the need to swap injected components for testing by defining profiles e.g. test, production etc.
The link to the blog post is here. The Spring team have today released the second milestone release of Spring 3.1.
You can use a special component scan for your test, that exclude the "normal" class and add the test class.
If you have several different test classes, then they should not have a #Component Annotation (or #Service, ...). Instead they should be loaded by an XML Bean declaration. So you can have different XML files for different setups.
<context:component-scan base-package="com.queomedia.sgcrm.base">
<context:exclude-filter expression="com\.example\.AImpl" type="regex"/>
</context:component-scan>
<bean class="com.example.ATestImpl"/>
Using Spring annotation config classes, code the #Bean methods to interfaces. The prod config can perform a componentscan on the high-level package(s) to load the prod objects and the test configs can individually specify beans to return the test versions of your objects. This works very well for component testing where faking service calls and DAO objects is necessary.
I'm currently learning the new Java EE 6 component models and am confused with the latest dependency injection mechanism. So here are my questions:
1) What is the difference between #Inject and #EJB
2) If I have a simple POJO that contains another POJOs (which one of them is the DAO code), what would be the better choice: #Inject or #EJB?
Can I mix #Inject and #EJB?
An example would be:
ClassA implements InterfaceA and has
an instance of ClassA_Adaptor
ClassA_Adaptor implements InterfaceAB
and has an instance of ClassB
ClassB implements InterfaceB and has
an instance of ClassB_Adaptor and an
instance DAO_ClassB
ClassB_Adaptor implements InterfaceB
and has an instance of ClassC
ClassC implements InterfaceBC and has
an instance of WebService_ClassC
DAO_ClassB will use JPA 2.0
(#PersistenceContext)
I'd like to inject all of them including the DAO and the WebService.
3) Is it a bad approach to only use transactional for certain operations but not for all?
As an example: Some methods in DAO_ClassB are your typical query, while other methods are "write" methods. Is it bad to not wrap the "READ" methods with transaction?
To my understanding, the DAO_ClassB can be wrapped with transaction using #EJB (inject the DAO_ClassB and make all methods transactional). How can I control it?
Sorry if some of the questions are confusing because I know only bits and pieces of the Java EE 6 new component model.
#EJB injects EJBs only, but #Inject can be used to inject POJOs rather than EJBs. However, #Inject requires that your archive be a BDA (contain beans.xml for EE 6, or implicitly in EE 7). #Inject also has additional CDI-specific capabilities (scopes, interceptors, etc.), but those capabilities incur extra overhead. Application servers have support for specifying #EJB bindings so that a deployer can choose the target EJB, but #Inject only allows the application developer to choose the target EJB (and it must exist in the application).
If the target is not an EJB, then you must not use #EJB.
It depends whether you're making multiple inter-related queries and then attempting to make business decisions. You need to understand isolation levels and take them into consideration, even for read-only operations.
From Adam Biens Weblog:
You can use both annotations to inject EJBs. Start with #Inject and if you encounter any problems, switch to #EJB.
#Inject does not have any methods / attributes--it is just a plain annotation:
#Target(value = {ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.FIELD})
#Retention(value = RetentionPolicy.RUNTIME)
#Documented
public #interface Inject {
}
On the other hand, the #EJB annotation allows you to pass additional information, which could be useful to reference remote EJBs, or EJBs which cannot be simple injected in the "Convention over Configuration" style:
#Target(value = {ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
#Retention(value = RetentionPolicy.RUNTIME)
public #interface EJB {
public String name() default "";
public String beanName() default "";
public Class beanInterface() default Object.class;
public String mappedName() default "";
}
#Inject is more general than EJB and is part of CDI specification. So if you want to use #Inject, you need an implementation of it in your server.
For POJOs (not EJBs) you have to use #Inject.
Does anyone know how to run unit tests for Liferay portlets? I have found a lot of posts about it (e.g. http://agile-reflections.opnworks.com/2010/06/portlet-unit-testing-with-liferay-6.html) but none works nonetheless.
This may be overkill, but if you're looking for an Enterprise approach with continuous integration testing, this blog gives a very good example: Continuous integration on Liferay: running your Selenium 2 tests on the Tomcat 6 bundle
Unit testing Liferay portlets is quite complicated when ServiceBuilder is utilized.
The reason is that it generates quite heavy services that contain references not only to beans within Portlet, but even to the Portal beans generated by ServiceBuilder.
There are tools like InitUtil.init(); that lets you at least instantiate and use ServiceBuilder entities... not EntityServices though. For that you'd have to use SpringUtil.loadContext(); that requires
System.setProperty("external-properties", "testing.properties");
where testing.properties contains :
spring.configs=META-INF/ext-spring.xml,\
META-INF/base-spring.xml,\
META-INF/dynamic-data-source-spring.xml,\
META-INF/infrastructure-spring.xml,\
META-INF/shard-data-source-spring.xml,\
META-INF/hibernate-spring.xml,\
META-INF/portlet-spring.xml
These are spring definitions to be loaded for testing application context. It all would be OK, but beans from portlet-spring.xml are those heavy services containing references to Portal bean definitions like ResourceService, UserLocalService, CounterLocalService and you would have to load even META-INF/portal-spring.xml and trust me, it's not that easy cause then you'd have to load quite a lot of other stuff.
THE ANSWER:
The truth is, that you most likely won't have to unit test portlet SB services, never. They represent entities with persistence and service layer around. Something that is not to be tested. You just have to mock them and stub their methods, right ?
And the best way for junit and integration testing as to mocking is not using *LocalServiceUtil static classes in your application, because it is almost unmockable.
You just need to create a Spring FactoryBean :
public class PortalFactoryBean implements FactoryBean {
private Class type;
public void setType(final Class type) {
this.type = type;
}
#Override
public Object getObject() throws Exception {
return PortalBeanLocatorUtil.locate(type.getName());
}
#Override
public Class getObjectType() {
return type;
}
}
public class PortletFactoryBean implements FactoryBean {
private Class type;
public void setType(final Class type) {
this.type = type;
}
#Override
public Object getObject() throws Exception {
return PortletBeanLocatorUtil.locate(type.getName());
}
#Override
public Class getObjectType() {
return type;
}
}
<bean id="somePortalBean" class="example.spring.PortalFactoryBean" lazy-init="true">
<property name="type" value="com.liferay.some.util.SomeService"/>
</bean>
<bean id="somePortletBean" class="example.spring.PortletFactoryBean" lazy-init="true">
<property name="type" value="com.example.SomeService"/>
</bean>
#Autowired
private SomeService somePortalBean;
Writing unit/integration tests for this portlet would be quite easy, right ? You just create a spring context for testing and you mock these services :
Using Service Builder is worth it, but you must have some Spring knowledge and play with it for some time. Then it spares a lot of time because it is easy to maintain.
You need to have some third party libraries on classpath.
THe key point is having even portal-impl.jar and other portal dependencies on classpath and having InitUtil.initWithSpring(boolean); load up core spring xml configs that you specify in spring-ext.properties in spring.congigs property, only those services you need. You may need no portal services and only the portlet ones, but this is a problem because your portlet services generated by service builder use the portal services.
Using service builder just needs good knowledge of spring and classloading.
But you need to understand the infrastructure before doing that. There are quite a lot of hacks needed... Like
BeanLocator beanLocator = new BeanLocatorImpl(PortalClassLoaderUtil.getClassLoader(), ac);
PortletBeanLocatorUtil.setBeanLocator("portlet", beanLocator);