NoSuchMethodError in Jetty with Spring Data Mongo custom repository - spring

I have a small web application in development using Maven, Spring MVC and Spring Data Mongo. I am getting a java.lang.NoSuchMethodError when one of my Controllers attempts to access a method defined in a custom repository. The same method works fine when exercised via a JUnit 4 test extending AbstractJUnit4SpringContextTests and using a near-identical XML configuration file.
Standard repository:
public interface IndividualRepository extends MongoRepository<Individual, String>, IndividualRepositoryCustom {
...
}
Custom interface:
public interface IndividualRepositoryCustom {
Individual findByIdentifier(String identifierType, String identifierValue);
}
Custom implementation:
public class IndividualRepositoryImpl implements IndividualRepositoryCustom {
#Autowired
private MongoTemplate mongoTemplate;
#Override
public Individual findByIdentifier(String identifierType, String identifierValue) {
String locator = String.format("identifiers.%s", identifierType);
return mongoTemplate.findOne(query(where(locator).is(identifierValue)), Individual.class);
}
}
dataaccess-config.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mongo="http://www.springframework.org/schema/data/mongo"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/data/mongo
http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd">
<mongo:repositories base-package="com.myco.dataaccess"/>
<mongo:mongo host="mongo.myco.com" port="27017"/>
<mongo:db-factory dbname="test" mongo-ref="mongo"/>
<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
<constructor-arg ref="mongo"/>
<constructor-arg value="test"/>
</bean>
</beans>
In my JUnit test I have (excerpt):
#Autowired
private IndividualRepository individualRepo;
...
List<Individual> foundList = individualRepo.findAll();
assertNotNull(foundList);
assertTrue(foundList.size() > 0);
Individual found = individualRepo.findByIdentifier("someid", "123456");
assertNotNull(found);
assertEquals("Bob", found.getFirstName());
The test passes fine, calling both findAll() (standard Repository method) and findByIdentifier() (custom method). The latter fails with NoSuchMethodError when called by a Controller running in a web application in Jetty, while the same Controller can call findAll() with no issues.

This turned out to be nothing to do with Spring Data, but an issue with the way I was using the maven-jetty-plugin with my multi-module build.
Basically, I was running mvn jetty:run for my web module which had a dependency on my dataaccess module (where my JUnit tests lived). As I was rebuilding the project with mvn clean package, the latest versions were not being placed in my local repo, and therefore were not being picked up by the mvn jetty:run process running alongside my build process. Problem was solved by building with mvn clean install.
So, as usual, the error message was spot on - the method indeed did not exist in the version of the JAR that Jetty was being supplied.

Related

Spring XD Java config doesn't load xml resource

I am using Spring XD to create stream twittersearch then wired to my tweet-processor then wired to log.
I used Java config class all fine no issues, then I wanted to add applicationContext.xml in my ModuleConfiguration class using #ImportResource
#Configuration
#ImportResource("config/applicationContext.xml")
#EnableIntegration
public class ModuleConfiguration {
#Bean
MessageChannel input() {
return new DirectChannel();
}
#Bean
MessageChannel output() {
return new DirectChannel();
}
#Autowired
TweetProcessor tweetProcessor;
#Bean
freemarker.template.Configuration configuration() {
return new freemarker.template.Configuration(freemarker.template.Configuration.VERSION_2_3_23);
}
}
And the applicationContext.xml content:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>file:/apps/conf/application.properties</value>
</list>
</property>
</bean>
</beans>
And my stream definition: stream create --name JustCreate --definition "twittersearch --query=Java | tweet-processor | log" --deploy
When the stream deployed I got error:
2015-10-21T11:26:26+0800 1.2.1.RELEASE WARN twitterSource-1-1 twitter.TwitterSearchChannelAdapter - Exception while reading stream.
org.springframework.messaging.MessageDeliveryException: Dispatcher has no subscribers for channel 'singlenode:default,admin,singlenode,hsqldbServer:9393.JustCreate.0'.; nested exception is org.springframework.integration.MessageDispatchingException: Dispatcher has no subscribers
I have tried also using spring-module.xml approach (not using Java config at all) and that approach works.
But I am just curious whether Spring XD Java config not supporting #ImportResource annotation.
Thanks.
Spring XD creates an application context in the normal normal way from an XML or #Configuration class once it locates and resolves the configuration resources. XD looks in the config directory. If it finds a .xml or or .groovy file, it will use that file to create the application context. If not, it will look for a .properties file and a base_packages property to scan for #Configuration classes. Since you have an XML file in the config directory, the #Configuration is being ignored. To import resources put them in a different path. This can be a sub-directory of config or a different top level directory. This is discussed in detail in the Modules section of the XD reference guide.

Issues while running JUnit on maven project using Spring JTA

I have a Spring + Hibernate project deployed on JBoss 5. It was using Ant earlier and recently I have modified the project structure to use Maven 2. But all the code and config files are the same.
I am using Spring JTA for transaction management in my project. I am able to perfecly buid the project and deploy it on JBoss. But when I try to execute the JUnit tests it gives me the following error:
java.lang.IllegalStateException: No JTA UserTransaction available - specify either 'userTransaction' or 'userTransactionName' or 'transactionManager' or 'transactionManagerName'
at org.springframework.transaction.jta.JtaTransactionManager.checkUserTransactionAndTransactionManager(JtaTransactionManager.java:473)
at org.springframework.transaction.jta.JtaTransactionManager.afterPropertiesSet(JtaTransactionManager.java:413)
The wierd thing is that this was working perfeclty fine when I was using Ant. It started coming after the migration to maven.
This is the entry in spring-jpa-conf.xml file:
<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager" >
</bean>
And this is the Junit code:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "classpath:spring-conf.xml" })
#Transactional(value = "transactionManager")
public abstract class LocalUsersTestBase {
#PersistenceContext(unitName="books-lemf")
protected EntityManager entityManager;
protected void getUsersDetails(List<Users> out) {
..........
}
I also tried to add a property in the config file entry as shown here:
<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager" >
<property name="userTransactionName" value="java:/TransactionManager"></property>
</bean>
But it gives the error:
Caused by: org.springframework.transaction.TransactionSystemException: JTA UserTransaction is not available at JNDI location [java:/TransactionManager]; nested exception is javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file: java.naming.factory.initial
at org.springframework.transaction.jta.JtaTransactionManager.lookupUserTransaction(JtaTransactionManager.java:548)
at org.springframework.transaction.jta.JtaTransactionManager.initUserTransactionAndTransactionManager(JtaTransactionManager.java:425)
at org.springframework.transaction.jta.JtaTransactionManager.afterPropertiesSet(JtaTransactionManager.java:412)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1460)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1400)
... 37 more
Caused by: javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file: java.naming.factory.initial
at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:645)
at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:288)
at javax.naming.InitialContext.getURLOrDefaultInitCtx(InitialContext.java:325)
Please help.
Thanks!!
This is my complete spring config file:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jee="http://www.springframework.org/schema/jee"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager" >
</bean>
<jee:jndi-lookup id="books-pu"
jndi-name="java:/books-emf"
cache="true"
lookup-on-startup="false"
proxy-interface="javax.persistence.EntityManagerFactory"
/>
<jee:jndi-lookup id="booksDataSource" jndi-name="java:/books-ds"/>
</beans>
Firsty, from spring reference documentation
If you use JTA in a Java EE container then you use a container
DataSource
, obtained through JNDI,
in conjunction with Spring’s
JtaTransactionManager
. This is what the JTA and JNDI lookup version
would look like:
The
JtaTransactionManager
does not need to know about the
DataSource
, or any other specific
resources, because it uses the container’s global transaction management infrastructure
then when you run the tests you need to a environment container managed to get a JTA User Transaction. In addition can you share with us the complete spring configuration

Getting persistence.xml error while integrating jBPM 5.4 into a J2EE web app

I have been having trouble getting "jBPM integrated into a web app" while using Eclipse (Kepler). As a test I am simply trying to replicate the code found in the jBPM Full Installer's evaluation sample into the template code produced by a Maven JavaEE6 Archetype. I have noted my steps below so that the problem can be easily reproduced.
1) Add to the JBoss standalone.xml:
<datasource jndi-name="java:jboss/jdbc/jbpm-ds" pool-name="jBPMDS" enabled="true" use-java-context="true">
<connection-url>jdbc:h2:mem:test;DB_CLOSE_DELAY=-1</connection-url>
<driver>h2</driver>
<security>
<user-name>sa</user-name>
<password>sa</password>
</security>
</datasource>
2) JBoss Central > Maven Project > filter on "javaee6" (to create the "myservlet" Project):
Archetype = jboss-javaee6-webapp
Accept all defaults
3) Set src\main\resources\META-INF\persistence.xml to contain:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0"
xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="primary">
<!-- If you are running in a production environment, add a managed
data source, the example data source is just for proofs of concept! -->
<jta-data-source>java:jboss/datasources/ExampleDS</jta-data-source>
<properties>
<!-- Properties for Hibernate -->
<property name="hibernate.hbm2ddl.auto" value="create-drop" />
<property name="hibernate.show_sql" value="false" />
</properties>
</persistence-unit>
</persistence>
4) Add a jBPM Runtime by pointing at the \runtime folder from the jBPM Full Installer.
5) Select the jBPM Perspective, right click the myservlet Project > Convert to jBPM Project.
6) Add to the Deployment Assembly the Java Build Path Entries > jBPM Library.
7) In src\main\java\com\mycompany\mywebapp\controller add to (arbitrarily chosen) MemberRegistration.java (which was automatically created as part of the Project) the following which comes from the evaluation sample code:
import java.util.HashMap;
import java.util.Map;
import org.drools.KnowledgeBase;
import org.drools.builder.KnowledgeBuilder;
import org.drools.builder.KnowledgeBuilderFactory;
import org.drools.builder.ResourceType;
import org.drools.io.ResourceFactory;
import org.drools.logger.KnowledgeRuntimeLogger;
import org.drools.logger.KnowledgeRuntimeLoggerFactory;
import org.drools.runtime.StatefulKnowledgeSession;
import org.jbpm.process.workitem.wsht.HornetQHTWorkItemHandler;
8) In this same module, in register() add the following which also comes from the evaluation sample code:
try {
// load up the knowledge base
KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
kbuilder.add(ResourceFactory.newClassPathResource("Evaluation.bpmn"), ResourceType.BPMN2);
KnowledgeBase kbase = kbuilder.newKnowledgeBase();
StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();
HornetQHTWorkItemHandler humanTaskHandler = new HornetQHTWorkItemHandler(ksession);
humanTaskHandler.setIpAddress("127.0.0.1");
humanTaskHandler.setPort(5153);
ksession.getWorkItemManager().registerWorkItemHandler("Human Task", humanTaskHandler);
KnowledgeRuntimeLogger logger = KnowledgeRuntimeLoggerFactory.newThreadedFileLogger(ksession, "test", 1000);
// start a new process instance
Map<String, Object> params = new HashMap<String, Object>();
params.put("employee", "krisv");
params.put("reason", "Yearly performance evaluation");
ksession.startProcess("com.sample.evaluation", params);
System.out.println("Process started ...");
logger.close();
} catch (Throwable t) {
t.printStackTrace();
}
Upon deploying along with the six jBPM WARs we get this error:
...
Caused by: java.lang.IllegalArgumentException: JBAS011470: Persistence unitName was not specified and there are 2 persistence unit definitions in application deployment "myservlet.war". Either change the application to have only one persistence unit definition or specify the unitName for each reference to a persistence unit.
I have confirmed that there is exactly one persistence.xml file anywhere in the deployed myservlet folder (it is in jboss-as-7.1.1.Final\standalone\deployments\myservlet.war\WEB-INF\classes\META-INF).
Can someone explain what this error means and how to eliminate it?
My guess is that somewhere along all those configured .xml you made some mistake that's not that clear. I know how much a pain in the a** that can be. I've written a small tutorial on how to configure persistence for JBPM using JBoss AS here. I suggest you follow it step by step to re-configure your project.
Hope it solves your problem!

Run a testsuite in multiple environment

I want to run my test suite in multiple environment like below:
ApplicationContextTest.class
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration("/application-context.xml")
public class MyTest{
#Autowired
private ApplicationContext applicationContext;
#Test
public void test1() {
((ConfigurableEnvironment)applicationContext.getEnvironment()).setActiveProfiles("env1");
((GenericXmlApplicationContext)applicationContext).refresh();
}
#Test
public void test2() {
((ConfigurableEnvironment)applicationContext.getEnvironment()).setActiveProfiles("env2");
((GenericXmlApplicationContext)applicationContext).refresh();
}
}
applicationContext.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<beans profile="env1">
</beans>
<beans profile="env2">
</beans>
When I run test, I got an exception
Caused by: java.lang.IllegalStateException: GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once
Are there any ways to set Active Profile after ApplicationContext started up?
Or Any solution to solve above exception?
Thanks.
The normal way to choose one or more specific profile(s) is to set a system property when running the tests
-Dspring.profiles.active=env1
You can also set one or more profile(s) as default with the system property
-Dspring.profiles.default=env1
I normally do this in a static init method of my test
#BeforeClass
public static void init() {
// set default spring test profile
System.setProperty("spring.profiles.default", "default");
}
You will find some information if you search for these properties (If you need a Spring code reference you have to look at the AbstractEnvironment class).
I do not know of any way how to change the profile after startup. In this case you may have to use a new JVM on each test (can e.g. be done by the maven surefire plugin using the reuseForks setting). Or even better place the tests that use the same profile in the same test class and set the profile as needed.
IMHO a test should not depend on a specific profile. A test should pass - whatever profile is used. Than you can easily change e.g. between test (mock) or 'real' environments.

Overriding System property in Spring PropertyPlaceHolderConfigurer for integration testing

I'm using a System property to define the location for an environment-specific properties file. However, I would like to override that value to something different for integration tests.
Here's my production spring setup. I'm using a custom PropertyPlaceholderConfigurer to resolve some encrypted property file values, but that's not important here:
<-- Spring configuration in file service-spring-beans.xml -->
<bean class="com.mycompany.MyPropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:properties/${MY_ENVIRONMENT}/${MY_ENVIRONMENT}.properties</value>
</list>
</property>
<property name="ignoreResourceNotFound" value="false"/>
<property name="ignoreUnresolvablePlaceholders" value="true"/>
</bean>
At runtime, we define the value of MY_ENVIRONMENT as a Java system property. This all works as expected. However, for integration tests, I would like to define MY_ENVIRONMENT as "inttest", so the integration-test specific property file properties/inttest/inttest.properties is loaded.
I've tried to use a spring context loaded by the integration-test to set up a String bean with the id MY_ENVIRONMENT:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">
<context:component-scan base-package="com.mycompany.myclasses"/>
<bean class="java.lang.String" id="MY_ENVIRONMENT">
<constructor-arg value="inttest"/>
</bean>
<!-- this imports the production spring context -->
<import resource="classpath:service-spring-beans.xml"/>
</beans>
However, the value of MY_ENVIRONMENT is not resolved , and I get this error when running the integration tests.
Caused by:
org.springframework.beans.factory.BeanInitializationException: Could
not load properties; nested exception is
java.io.FileNotFoundException: class path resource
[properties/${MY_ENVIRONMENT}/${MY_ENVIRONMENT}.properties] cannot
be opened because it does not exist
How can I override MY_ENVIRONMENT at inttest time without passing a System property to the JVM?
Since I was using the maven surefire plugin to run integration tests, the simplest solution turned out to be setting the system property using the surefire plugin configuration, like this:
<configuration>
<systemPropertyVariables>
<MY_ENVIRONMENT>inttest</MY_ENVIRONMENT>
</systemPropertyVariables>
<!-- ... -->
<configuration>
Since you don't want to use profiles, you can create multiple contexts and just include the proper context files for what you want. So for integration testing you have have your application-context.xml and an integration-property-context.xml file while, in the prod environment you would include the application-context.xml with a production-property-context.xml file. I've seen this approach used heavily to switch datasources between dev and prod where dev would be a BasicDataSource implementation and the prod environment references a JDNI DataSource.
This approach will help you avoid ActiveProfiles, but you run in to the problem of managing duplicate beans possibly which ActiveProfiles really simplified down.
you could look at overriding your whole property placeholder implementation using active profiles. that is, the default (no profile) launches your property placeholder, but a test profile (e.g. 'test') could create a new test bean for the property placeholder.
one of the challenges with property placeholder is that its loaded at the very early stages of the application context startup, so a normal override bean may not work.

Resources