I'm trying to add a listener for a service task when creating a new business process. I've found the following example:
package ru.psb.alfresco.workflow.listeners;
import org.activiti.engine.delegate.DelegateTask;
import org.alfresco.repo.workflow.activiti.tasklistener.ScriptTaskListener;
public class ShowDocList extends ScriptTaskListener {
private static final long serialVersionUID = 1L;
org.alfresco.repo.jscript.ScriptLogger log = new org.alfresco.repo.jscript.ScriptLogger();
#Override
public void notify(DelegateTask arg0) {
...
}
}
But eclipse doesn't know anything about the import org.alfresco.repo.workflow.activiti.tasklistener.ScriptTaskListener;
So what dependency do I need to add for this package? Google doesn't give me the appropriate result.
The org.alfresco.repo.workflow.activiti.tasklistener.ScriptTaskListener class is contained in the following artifact:
org.alfresco:org.alfresco-repository.
It is not available in maven central, but instead it can be found in the following repository:
https://maven.alfresco.com/nexus/content/groups/public/
So in your pom you would need to add the following:
<project>
...
<repositories>
...
<!-- define the alfresco maven repository -->
<repository>
<id>Alfresco Maven Repository</id>
<url>https://maven.alfresco.com/nexus/content/groups/public/</url>
</repository>
...
</repositories>
...
<dependencies>
<!-- add dependency to alfresco-repository -->
<dependency>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-repository</artifactId>
<version>5.0.c</version>
</dependency>
</dependencies>
...
</project>
Related
I'm completly new to cassandra, so my error might be obvious.
I'm trying to create an application with spring boot (version 2.3.0.M2) that contacts a cassandra (version 3.11.6) installed in localhost.
I've got an java.lang.IllegalStateException with the message:
Since you provided explicit contact points, the local DC must be explicitly set (see basic.load-balancing-policy.local-datacenter in the config, or set it programmatically with SessionBuilder.withLocalDatacenter). Current contact points are: Node(endPoint=localhost:9042, hostId=16a785a4-eaf3-4a4d-a216-5244d75206aa, hashCode=7b0b99d7)=datacenter1. Current DCs in this cluster are: datacenter1
My pom is the following one:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.0.M2</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.test</groupId>
<artifactId>cassandra</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>cassandra</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-cassandra</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
</pluginRepository>
</pluginRepositories>
</project>
In the application code, I've got a the following configuration class:
public class CassandraConfig extends AbstractCassandraConfiguration {
public static final String KEYSPACE = "test_keyspace";
#Override
public SchemaAction getSchemaAction() {
return SchemaAction.CREATE_IF_NOT_EXISTS;
}
#Override
protected List<CreateKeyspaceSpecification> getKeyspaceCreations() {
CreateKeyspaceSpecification specification = CreateKeyspaceSpecification.createKeyspace(KEYSPACE);
return Arrays.asList(specification);
}
#Override
protected List<DropKeyspaceSpecification> getKeyspaceDrops() {
return Arrays.asList(DropKeyspaceSpecification.dropKeyspace(KEYSPACE));
}
#Override
protected String getKeyspaceName() {
return KEYSPACE;
}
#Override
public String[] getEntityBasePackages() {
return new String[]{"com.test.cassandra.entity"};
}
}
My properties file contains the following configuration:
spring.data.cassandara.keyspace-name=test_keyspace
spring.data.cassandra.contact-points=localhost
spring.data.cassanda.port=9042
spring.data.cassandra.schema-act=create_if_not_exists
I also have tried with
spring.data.cassandra.contact-points=dc1
When I execute the application, I got see from the logs that I'm using the following version
DataStax Java driver for Apache Cassandra(R) (com.datastax.oss:java-driver-core) version 4.4.0
In the cassandra-rackdc.properties I've set the name to
dc=dc1
I've done several test adding configuration parameters, even adding an application.conf to the classpath as described datastax documentation, but didn't have any success. Any clue where should I do it?
Simply add
spring.data.cassandra.local-datacenter=DC1
to your application.properties file, where DC1 your local datacenter name (default DC1).
Since Spring Boot 2.3.0.X you need to explicitly provide the name of the local datacenter (because of the added Cassandra driver 4.X support which requires local datacenter to be set explicitly). You can do this by overrirding the getLocalDataCenter method in AbstractSessionConfiguration. AbstractCassandraConfiguration extends this class so you just need to add in your CassandraConfig class:
#Override
protected String getLocalDataCenter() {
return "dc1";
}
Run nodetool status in the Cassandra shell. It gives you the datacenter name.
> root#d21e7b0dfc44:/# nodetool status
Datacenter: datacenter1
=======================
Status=Up/Down
|/ State=Normal/Leaving/Joining/Moving
-- Address Load Tokens Owns (effective) Host ID Rack
UN 172.17.0.2 143.37 KiB 16 ? a3584baf-0665-474b-84e9-ba30528a7781 rack1
root#d21e7b0dfc44:/#
In my case, it is "datacenter1". This goes inside the properties file like so:
spring.data.cassandra.local-datacenter=datacenter1
There's actually a different config needed for Apache Cassandra to truly work with the new spring versions. It took me about 50 hours of searching before finding this out on this documentation - https://docs.spring.io/spring-data/cassandra/docs/current/reference/html/#cassandra.cassandra-java-config
You'll need to create a new config file as specified there. To do this, follow thus:
Create a new package named config
Create a .java class file in the package named - CassandraConfig
Copy and paste the below code into it.
#Configuration public class CassandraConfig { public #Bean CqlSession session() { return CqlSession.builder().withKeyspace("mykeyspacename").build(); } }
Note, change the Keyspace name to your Keyspace name defined in your property file. If you have not created a Keyspace, start Cassandra server on your system, login to the cqlsh on the terminal or cmd by issuing cqlsh, and issue this command -
CREATE KEYSPACE IF NOT EXISTS mykeyspacename WITH REPLICATION = { 'class' : 'SimpleStrategy', 'replication_factor' : 1 } AND DURABLE_WRITES = true ;
By now, when you start the spring boot app, it should run without any error.
Since Spring Boot 3.0 Cassandra properties' prefix is spring.cassandra.*, not spring.data.cassandra.* (specifically since 3.0.0-M5, as can be seen from #ConfigurationProperties.prefix value here and here),
so you need to write
spring.cassandra.local-datacenter=datacenter1
in your application.properties file to set local datacenter
Its mentioned in your error logs "Current DCs in this cluster are: datacenter1"
Just add spring.data.cassandra.local-datacenter=datacenter1 in application.properties
I solved this problem by setting local datacenter like this :
application properties file : cassandra.local.datacenter=datacenter1
#Value("${cassandra.local.datacenter}")
private String localDatacenter;
#Bean
#Override
public CqlSessionFactoryBean cassandraSession() {
CqlSessionFactoryBean cqlSessionFactoryBean = new CqlSessionFactoryBean();
cqlSessionFactoryBean.setUsername(username);
cqlSessionFactoryBean.setPassword(password);
cqlSessionFactoryBean.setKeyspaceName(keySpace);
cqlSessionFactoryBean.setLocalDatacenter(localDatacenter);
cqlSessionFactoryBean.setPort(port);
cqlSessionFactoryBean.setContactPoints(contactPoint);
return cqlSessionFactoryBean;
}
Note : This is not all of the configuration code. I just wanted to show local datacenter configuration by this code snippet.
I'm testing one prototype for spring-cloud using #RefreshScope annotation. I'm using one external property file for that. Which I have provided and configured in runtime argument.
pom.xml dependency
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.1.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>com.proto.reload</groupId>
<artifactId>CachingService</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>CachingService</name>
<description>Demo project for cache</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-context</artifactId>
<version>1.1.8.RELEASE</version>
</dependency>
<!-- <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-config-client</artifactId>
<version>1.1.3.RELEASE</version> </dependency> -->
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
This is main class
package com.proto.reload;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.ApplicationPidFileWriter;
#SpringBootApplication
public class CachingServiceApplication {
public static void main(String[] args) {
if (args.length == 0) {
System.out.println("Invalid Commandline argument. Please provide Consumer Properties file.");
System.exit(0);
}
new SpringApplicationBuilder(CachingServiceApplication.class)
.listeners(new ApplicationPidFileWriter())
.properties("spring.config.name:" + args[0].replaceAll(".properties", ""))
.build()
.run(args);
while (true) {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(ConfigClass.getName());
}
}
}
Config class having #RefreshScope annotation
package com.proto.reload;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.context.annotation.Configuration;
#Configuration
#RefreshScope
public class ConfigClass {
private static String name;
public static String getName() {
return name;
}
#Value("${app.prop.name}")
public void setName(String name) {
this.name = name;
}
}
And this is property file I'm passing through argument
app.prop.name=FirstOldValue
spring.pid.file=TestOne.pid
When I run this code, I get the following error.
12:38:41.051 [main] DEBUG org.springframework.boot.context.logging.ClasspathLoggingApplicationListener - Application failed to start with classpath: [file:/C:/Program%20Files/Java/jre1.8.0_191/lib/resources.jar, file:/C:/Program%20Files/Java/jre1.8.0_191/lib/rt.jar, file:/C:/Program%20Files/Java/jre1.8.0_191/lib/jsse.jar, file:/C:/Program%20Files/Java/jre1.8.0_191/lib/jce.jar, file:/C:/Program%20Files/Java/jre1.8.0_191/lib/charsets.jar, file:/C:/Program%20Files/Java/jre1.8.0_191/lib/jfr.jar, file:/C:/Program%20Files/Java/jre1.8.0_191/lib/ext/access-bridge-64.jar, file:/C:/Program%20Files/Java/jre1.8.0_191/lib/ext/cldrdata.jar, ...]
12:38:41.105 [main] ERROR org.springframework.boot.SpringApplication - Application run failed
java.lang.NoSuchMethodError: org.springframework.boot.builder.SpringApplicationBuilder.<init>([Ljava/lang/Object;)V
at org.springframework.cloud.bootstrap.BootstrapApplicationListener.bootstrapServiceContext(BootstrapApplicationListener.java:120)
at org.springframework.cloud.bootstrap.BootstrapApplicationListener.onApplicationEvent(BootstrapApplicationListener.java:84)
at org.springframework.cloud.bootstrap.BootstrapApplicationListener.onApplicationEvent(BootstrapApplicationListener.java:62)
at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:172)
at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:165)
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:139)
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:127)
at org.springframework.boot.context.event.EventPublishingRunListener.environmentPrepared(EventPublishingRunListener.java:75)
at org.springframework.boot.SpringApplicationRunListeners.environmentPrepared(SpringApplicationRunListeners.java:54)
at org.springframework.boot.SpringApplication.prepareEnvironment(SpringApplication.java:347)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:306)
at com.proto.reload.CachingServiceApplication.main(CachingServiceApplication.java:19)
Am I using #RefreshScope in wrong way ?
This code works fine when I remove dependency and #RefreshScope, but its not updating property value at runtime. My goal is to load modified property value at runtime.
1.1.8.RELEASE for Spring Cloud is part of the Camden Release train which is for Spring Boot 1.4.x releases.
Please see the Release Trains section for what release train to use for your Spring Boot version
https://spring.io/projects/spring-cloud
Currently they are,
Release Train Boot Version
Greenwich 2.1.x
Finchley 2.0.x
Edgware 1.5.x
Dalston 1.5.x
As your using spring boot 2.1.1 your dependency management should look like the below, note as Greenwich doesn't have a RELEASE yet you need to add the milestone repository.
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>http://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Greenwich.RC2</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-context</artifactId>
</dependency>
</dependencies>
try this
#RefreshScope
public class ConfigClass {
#Value("${app.prop.name}")
private static String name;
public static String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Add cloud context depedency and try again
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-context</artifactId>
<version>1.1.8.RELEASE</version>
</dependency>
Update :
it is just not a valid use case to have #Configuration and #RefreshScope on the same element. As per this URL thread : https://github.com/spring-cloud/spring-cloud-config/issues/43
I am using a REST web service that queries data from Apache Solr. I'm using Spring boot + data with Solr repositories.
I do not know how to interconnect as service, repository, and controller layers.
I have the following structure
Controller:
#RestController
public class ImageSearchController {
private final Logger log = LoggerFactory.getLogger( this.getClass( ) );
#Resource ImageService imageService;
....
}
Main to SpringBootApplication:
#SpringBootApplication
public class Application extends SpringBootServletInitializer{
public static void main( String[ ] args ) {
SpringApplication.run( Application.class , args );
}
}
Service:
public interface ImageService {
List< Image > searchTerm( String searchTerm );
List< Image > search(String imgSrc , String imgTitle);
List< Image > searchByImgSrc( String searchTerm );
List< Image > findAll( );
}
Service Impl:
#Service
public class ImageServiceImpl implements ImageService {
#Resource
private ImageRepository repository;
#Override
public List< Image > search( String imgSrc , String imgTitle ) {
return repository.findByImgSrcContainsOrImgTitleContains( imgSrc , imgTitle );
}
....
}
Repository (Spring Data):
public interface ImageRepository extends SolrCrudRepository< Image , String > {
public List< Image > findAll( );
...
}
Pom.xml:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.solr/solr-solrj -->
<dependency>
<groupId>org.apache.solr</groupId>
<artifactId>solr-solrj</artifactId>
<version>5.1.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.data/spring-data-solr -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-solr</artifactId>
<version>2.1.1.RELEASE</version>
</dependency>
</dependencies>
...
<repositories>
<repository>
<id>spring-releases</id>
<url>https://repo.spring.io/libs-release</url>
</repository>
<repository>
<id>spring-milestone</id>
<name>Spring Milestone Maven Repository</name>
<url>http://repo.springsource.org/libs-milestone</url>
</repository>
</repositories>
Logs of application
How to create the bean and access the controller in the service layer?
How to configure solr client with rest web service ?
UPDATE
I upgraded the spring boot version from 1.4.3 to 1.5.1 and it worked. Honestly, I do not understand why.
Now I get another error, when accessing solr, the spring data duplicates the name of the core in solr. Any idea ?
Thanks
1st you don't need the service interface if you only have one implementation.
You do not access the controller in the service layer it's the other way around. Controller > Service >Repository(solr in your case)
Controller defines your API, Service defines your business layer and repository you should be using to access external resources (solr in your case)
So in the Controller you #Autowire the service and in the serice you #Autowire the Repository
First, you should inject your dependencies. I recommend constructor injection. In your case:
#Service
public class ImageServiceImpl implements ImageService {
private final ImageRepository repository;
#Autowired // no necessary in spring 4.3+
public ImageServiceImpl(ImageRepository repository) {
this.repository = repository;
}
The ImageRepository-Bean could not be found (Maybe you miss #EnableJpaRepositories) so spring is looking for a BeanFactory and finds a SolrRepositoryFactoryBean that requires a constructor-parameter of type (Class). Usually a Scanner of #EnableJpaRepositories constructs the SolrRepositoryFactoryBean but as long as #EnableJpaRepositories is missing (or configured wrong) the ImageRepository could not be constructed.
The Fix:
Add #EnableJpaRepositories to the Application and configure the parameters of the annotation.
I am trying to build rest service using Spring Boot. I am learning to implement it using the this Spring's guide. I have built the application using STS as a Maven application and the code is exact replica of the guide and when I try to run the application I get the below connection error
I also tried to run the github code for the same guide provided by Spring and that code also gives same the error as above. I am new to Spring Boot and any help would be appreciated.
Below is my code
App.java
package Greetings.Web_Services;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class App
{
public static void main( String[] args )
{
System.out.println("App Started");
SpringApplication.run(App.class, args);
}
}
Greetings.java
package Greetings.Web_Services;
public class Greetings {
private final long id;
private final String content;
public Greetings(long id, String content){
this.id = id;
this.content = content;
}
public long getId(){
return id;
}
public String getContent(){
return content;
}
}
GreetingsController.java
package Greetings.Web_Services;
import java.util.concurrent.atomic.AtomicLong;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
#RestController
public class GreetingsController {
private static final String template = "Hello, %s!";
private final AtomicLong counter = new AtomicLong();
#RequestMapping("/greeting")
public Greetings greeting(#RequestParam(value="name", defaultValue="World") String name) {
return new Greetings(counter.incrementAndGet(),
String.format(template, name));
}
}
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework</groupId>
<artifactId>gs-rest-service</artifactId>
<version>0.1.0</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.0.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency> -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>4.3.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<properties>
<java.version>1.8</java.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-releases</id>
<url>https://repo.spring.io/libs-release</url>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-releases</id>
<url>https://repo.spring.io/libs-release</url>
</pluginRepository>
</pluginRepositories>
</project>
GitHub link for the project of above code
Thanks!!
The code in the guide is correct and it was not working earlier for which I had also raised an issue in the GitHub community of the guide. Later when I updated the STS and restarted, it seems to work now. One of the modifier in the community also recommended the same after I explained the scenario. Hope this saves someone's time.
Am using the latest versions of Spring Boot, Spring JDBC, and Spring Rest...
My project is setup as a typical Maven project containing the following filesystem structure:
myproject
|
--src/main/java/com/myapp
--src/main/resource/application.properties
|
--src/test/java/com/myapp
--src/test/resources/application.properties
|
pom.xml
My application.properties are as follows (connecting to a local MySQL 5 database):
spring.datasource.url=jdbc:mysql://localhost:3306/testdb
spring.datasource.username=root
spring.datasource.password=
spring.datasource.name=testdb
spring.datasource.initialize=true
spring.datasource.driverClassName=com.mysql.jdbc.Driver
MyDAO:
public interface MyDao {
public List<App> findAllApps();
}
MyDaoImpl:
#Repository("myDao")
public class MyDaoImpl implements MyDao {
#Autowired
JdbcTemplate jdbcTemplate;
public List<App> findAllApps() {
List<App> apps = this.jdbcTemplate.query(
"select app_name from app",
new RowMapper<App>() {
public App mapRow(ResultSet rs, int rowNum) throws SQLException {
App app = new App();
app.setAppName(rs.getString("app_name"));
return app;
}
});
return apps;
}
}
Its called in MyService class using Dependency Injection:
#RestController
public class MyService {
#Autowired
#Qualifier("myDao")
MyDao myDao;
#RequestMapping(value = "/apps", method = RequestMethod.GET, consumes = "text/plain", produces = "application/json")
public void process() throws JsonParseException, IOException {
List<App> apps = myDao.findAllApps();
System.out.println(apps.toString());
}
}
This totally works as stated in my RestController...
But however, in a typical JUnit test:
public class MyServiceTest {
#Autowired
#Qualifier("myDao")
MyDao myDao;
#Test
public void process() {
List<App> apps = myDao.findAllApps();
}
}
The call to myDao.findAllApps() returns a NullPointerException...
I even tried running my app (using the embedded tomcat) first by issuing the following from the command line:
mvn spring-boot:run
However a non-database specific JUnit test works inside Eclipse or when I do:
mvn clean install
Question(s):
How can I set it up so I can run an integration test and it actually hits my database (or a mock db for that matter) from MyServiceTest?
Why is the dependency injection failing when trying to inject in MyServiceTest for Spring JDBC?
Is there a way to setup my unit tests to test Rest calls?
Many thanks for everyone who took the time to read this and many many thanks for the people that respond!
Here's my pom.xml (per Eddu's request):
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework</groupId>
<artifactId>myproject</artifactId>
<version>0.1.0</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.2.2.RELEASE</version>
</parent>
<properties>
<java.version>1.7</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-rest-webmvc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-releases</id>
<name>Spring Releases</name>
<url>https://repo.spring.io/libs-release</url>
</repository>
<repository>
<id>org.jboss.repository.releases</id>
<name>JBoss Maven Release Repository</name>
<url>https://repository.jboss.org/nexus/content/repositories/releases</url>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-releases</id>
<name>Spring Releases</name>
<url>https://repo.spring.io/libs-release</url>
</pluginRepository>
</pluginRepositories>
</project>
It seems you aren't loading Spring's context in your test so the dependency injection isn't performed. You should do something like:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes=Application.class) //Application being your
// Spring boot base config class
public class MyServiceTest { ... }
#Autowired
#Qualifier("myDao")
MyDao myDao;
You can have a look at an example in my github
Thanks everyone!
Steve - you were correct!
After much trial & tribulation, the #SpringApplicationConfiguration worked:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes=Application.class)
Eddu Melendez - I removed the spring-starter-data-jpa dependency with spring-boot-starter-jdbc and also removed the spring-jdbc dependency from my pom.xml file.
Thank you all for trying to help me solve this issue!