Neo4J Spring Data - Error adding element with #RelatedToVia relationship to index __rel_types__ using SpringCypherRestGraphDatabase - spring-data-neo4j

I'm working on Neo4j Spring Data project and have started using a "RelationshipEntity" and the "#RelatedToVia" relationship to better model some relationships.
The problem I'm having is if I run an embedded database everything is fine but when I run with a SpringCypherRestGraphDatabase I keep getting the error "Error adding element... to index __rel_types__":
Any pointers would be great!!
Stacktrace:
Caused by: java.lang.RuntimeException: Error adding element 52 className AlsoKnownAs to index __rel_types__
at org.neo4j.rest.graphdb.RestAPIImpl.addToIndex(RestAPIImpl.java:703)
at org.neo4j.rest.graphdb.RestAPICypherImpl.addToIndex(RestAPICypherImpl.java:683)
at org.neo4j.rest.graphdb.index.RestIndex.add(RestIndex.java:58)
at org.springframework.data.neo4j.support.typerepresentation.AbstractIndexBasedTypeRepresentationStrategy.add(AbstractIndexBasedTypeRepresentationStrategy.java:139)
at org.springframework.data.neo4j.support.typerepresentation.AbstractIndexBasedTypeRepresentationStrategy.addToTypesIndex(AbstractIndexBasedTypeRepresentationStrategy.java:131)
at org.springframework.data.neo4j.support.typerepresentation.AbstractIndexBasedTypeRepresentationStrategy.writeTypeTo(AbstractIndexBasedTypeRepresentationStrategy.java:74)
at org.springframework.data.neo4j.support.mapping.TRSTypeAliasAccessor.writeTypeTo(TRSTypeAliasAccessor.java:46)
at org.springframework.data.neo4j.support.mapping.TRSTypeAliasAccessor.writeTypeTo(TRSTypeAliasAccessor.java:26)
at org.springframework.data.convert.DefaultTypeMapper.writeType(DefaultTypeMapper.java:199)
at org.springframework.data.convert.DefaultTypeMapper.writeType(DefaultTypeMapper.java:186)
at org.springframework.data.neo4j.support.mapping.Neo4jEntityConverterImpl.write(Neo4jEntityConverterImpl.java:168)
at org.springframework.data.neo4j.support.mapping.Neo4jEntityPersister$CachedConverter.write(Neo4jEntityPersister.java:179)
at org.springframework.data.neo4j.support.mapping.Neo4jEntityPersister.persist(Neo4jEntityPersister.java:254)
at org.springframework.data.neo4j.support.mapping.Neo4jEntityPersister.persist(Neo4jEntityPersister.java:235)
at org.springframework.data.neo4j.support.Neo4jTemplate.save(Neo4jTemplate.java:365)
at org.springframework.data.neo4j.fieldaccess.RelatedToViaCollectionFieldAccessorFactory$RelatedToViaCollectionFieldAccessor.persistEntities(RelatedToViaCollectionFieldAccessorFactory.java:99)
at org.springframework.data.neo4j.fieldaccess.RelatedToViaCollectionFieldAccessorFactory$RelatedToViaCollectionFieldAccessor.setValue(RelatedToViaCollectionFieldAccessorFactory.java:93)
at org.springframework.data.neo4j.fieldaccess.ManagedFieldAccessorSet.updateValue(ManagedFieldAccessorSet.java:112)
at org.springframework.data.neo4j.fieldaccess.ManagedFieldAccessorSet.update(ManagedFieldAccessorSet.java:100)
at org.springframework.data.neo4j.fieldaccess.ManagedFieldAccessorSet.add(ManagedFieldAccessorSet.java:126)
RelationshipEntity
import org.springframework.data.neo4j.annotation.EndNode;
import org.springframework.data.neo4j.annotation.Fetch;
import org.springframework.data.neo4j.annotation.GraphId;
import org.springframework.data.neo4j.annotation.RelationshipEntity;
import org.springframework.data.neo4j.annotation.StartNode;
#RelationshipEntity(type = "AKA")
public class AlsoKnownAs {
#GraphId Long id;
String name;
#Fetch #StartNode private Person identity;
#Fetch #EndNode private Person pseudenom;
public AlsoKnownAs setNickname(String nickName){
this.name = nickName;
return this;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Person getIdentity() {
return identity;
}
public void setIdentity(Person identity) {
this.identity = identity;
}
public Person getPseudenom() {
return pseudenom;
}
public void setPseudenom(Person pseudenom) {
this.pseudenom = pseudenom;
}
}
Node Entity
import java.util.HashSet;
import java.util.Set;
import org.neo4j.graphdb.Direction;
import org.springframework.data.neo4j.annotation.Fetch;
import org.springframework.data.neo4j.annotation.GraphId;
import org.springframework.data.neo4j.annotation.NodeEntity;
import org.springframework.data.neo4j.annotation.RelatedTo;
import org.springframework.data.neo4j.annotation.RelatedToVia;
#NodeEntity
public class Person {
#GraphId Long id;
public String name;
public Person() {}
public Person(String name) { this.name = name; }
#RelatedTo(type="TEAMMATE", direction=Direction.BOTH)
public #Fetch Set<Person> teammates;
#RelatedToVia(type="AKA")
Set<AlsoKnownAs> identities;
public void worksWith(Person person) {
if (teammates == null) {
teammates = new HashSet<Person>();
}
teammates.add(person);
}
public String toString() {
String results = name + "'s teammates include\n";
if (teammates != null) {
for (Person person : teammates) {
results += "\t- " + person.name + "\n";
}
}
return results;
}
public void identify(Person person, String nickName) {
AlsoKnownAs aka = new AlsoKnownAs();
aka.setIdentity(this);
aka.setPseudenom(person);
aka.setName(nickName);
this.identities.add(aka);
}
}
POM:
<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>com.teralitic</groupId>
<artifactId>geonames</artifactId>
<version>0.0.1-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.2.3.RELEASE</version>
</parent>
<properties>
<spring-data-releasetrain.version>Fowler-RELEASE</spring-data-releasetrain.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-neo4j</artifactId>
<version>3.3.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-neo4j-rest</artifactId>
<version>3.3.0.RELEASE</version>
</dependency>
<dependency>
<groupId>javax.el</groupId>
<artifactId>javax.el-api</artifactId>
<version>2.2.4</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<jvmArguments>
-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5005
</jvmArguments>
</configuration>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-releases</id>
<name>Spring Releases</name>
<url>https://repo.spring.io/libs-release</url>
</repository>
<repository>
<id>neo4j</id>
<name>Neo4j</name>
<url>http://m2.neo4j.org/</url>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-releases</id>
<name>Spring Releases</name>
<url>https://repo.spring.io/libs-release</url>
</pluginRepository>
</pluginRepositories>
Edited
I can see the same issue was happening on an old Spring Data build:
https://build.spring.io/browse/SPRINGDATA-NIGHTLY-JOB1-697/test/case/92176623;jsessionid=5EE45702C67548804FEF985C00F5DAD2
Still investigating what might have caused that.

Still can't figure a way to fix this issue cleanly.
My only workaround so far was to replace
org.springframework.data.neo4j.rest.SpringCypherRestGraphDatabase
by the now deprecated
org.springframework.data.neo4j.rest.SpringRestGraphDatabase
I am now able to save #RelatedToVia relationships.

I'm having the exact same problem here.
I use spring-data-neo4j 3.3.0.RELEASE and spring-data-neo4j-rest 3.3.0.RELEASE, i had also to add manually spring-data-commons 1.10 (https://jira.spring.io/browse/DATAGRAPH-635)
Using the deprecated class solved the issue, but i'm not sure on my configuration since Michael Hunger said (here http://java.dzone.com/articles/spring-data-neo4j-330) to use the SpringCypherRestGraphDatabase....

Related

Task assignment email using Camunda-bpm-reactor

I am trying to re-implement Task Assignment Email using camunda-bpm-reactor. I am able to send email when I am using Java classes, but when I try to re-implement it by event bus it does not work.
I added the required dependency as
<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.camunda.bpm.quickstart</groupId>
<artifactId>camunda-quickstart-task-assignment-email</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<name>Task Assignment Email</name>
<properties>
<camunda.version>7.10.0</camunda.version>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<failOnMissingWebXml>false</failOnMissingWebXml>
</properties>
<dependencies>
<dependency>
<groupId>org.camunda.bpm.extension</groupId>
<artifactId>camunda-bpm-reactor-core</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>org.camunda.bpm</groupId>
<artifactId>camunda-engine</artifactId>
<version>${camunda.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-email</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.8.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.3.171</version>
<scope>test</scope>
</dependency>
<!-- redirect slf4j logging to jdk logging -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-jdk14</artifactId>
<version>1.7.12</version>
<scope>test</scope>
</dependency>
</dependencies>
<repositories>
<repository>
<id>camunda-bpm-nexus</id>
<name>camunda-bpm-nexus</name>
<url>https://app.camunda.com/nexus/content/groups/public</url>
</repository>
</repositories>
</project>
to the pom.xml file of the project. I created three classes as follows:
TaskAssignmentApplication.java file:
package org.camunda.bpm.quickstart;
import org.camunda.bpm.application.ProcessApplication;
import org.camunda.bpm.application.impl.ServletProcessApplication;
import org.camunda.bpm.engine.ProcessEngine;
import org.camunda.bpm.engine.ProcessEngineConfiguration;
import org.camunda.bpm.engine.impl.cfg.StandaloneInMemProcessEngineConfiguration;
import org.camunda.bpm.extension.reactor.CamundaReactor;
import org.camunda.bpm.extension.reactor.bus.CamundaEventBus;
#ProcessApplication("TaskAssignmentEmail")
public class TaskAssignmentApplication extends ServletProcessApplication {
private static ProcessEngineConfiguration CONFIGURATION = new StandaloneInMemProcessEngineConfiguration() {
{
// register the plugin
this.getProcessEnginePlugins().add(CamundaReactor.plugin());
this.databaseSchemaUpdate = DB_SCHEMA_UPDATE_DROP_CREATE;
this.jobExecutorActivate = false;
this.isDbMetricsReporterActivate = false;
}
};
private static ProcessEngine processEngine;
public static ProcessEngine processEngine() {
if (processEngine == null) {
processEngine = CONFIGURATION.buildProcessEngine();
}
return processEngine;
}
public static void init() {
CamundaEventBus eventBus = CamundaReactor.eventBus();
// create and register listeners
new TaskCreateListener(eventBus);
new TaskAssignmentListener();
}
}
TaskCreateListener.java file:
package org.camunda.bpm.quickstart;
import org.camunda.bpm.engine.delegate.DelegateTask;
import org.camunda.bpm.engine.delegate.TaskListener;
import org.camunda.bpm.extension.reactor.bus.CamundaEventBus;
import org.camunda.bpm.extension.reactor.bus.CamundaSelector;
#CamundaSelector(type = "userTask", event = TaskListener.EVENTNAME_CREATE, process = "TaskAssignmentEmail")
public class TaskCreateListener implements TaskListener {
public TaskCreateListener(CamundaEventBus eventBus) {
eventBus.register(this);
}
#Override
public void notify(DelegateTask delegateTask) {
delegateTask.setPriority(97);
delegateTask.addCandidateGroup("IT");
}
}
and TaskAssignmentListener.java file:
package org.camunda.bpm.quickstart;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.commons.mail.Email;
import org.apache.commons.mail.SimpleEmail;
import org.camunda.bpm.engine.IdentityService;
import org.camunda.bpm.engine.delegate.DelegateTask;
import org.camunda.bpm.engine.delegate.TaskListener;
import org.camunda.bpm.engine.identity.User;
import org.camunda.bpm.engine.impl.context.Context;
import org.camunda.bpm.extension.reactor.CamundaReactor;
import org.camunda.bpm.extension.reactor.bus.CamundaSelector;
#CamundaSelector(type = "userTask", event = TaskListener.EVENTNAME_ASSIGNMENT)
public class TaskAssignmentListener implements TaskListener {
private static final String HOST = "smtp.gmail.com";
private static final String USER = "camunda.bp#gmail.com";
private static final String PWD = "";
private final static Logger LOGGER = Logger.getLogger(TaskAssignmentListener.class.getName());
//private final Logger logger = LoggerFactory.getLogger(getClass());
public TaskAssignmentListener() {
CamundaReactor.eventBus().register(this);
}
#Override
public void notify(DelegateTask delegateTask) {
//CamundaReactor.eventBus().register(new TaskCreateListener(null));
String assignee = delegateTask.getAssignee();
String taskId = delegateTask.getId();
if (assignee != null) {
// Get User Profile from User Management
IdentityService identityService = Context.getProcessEngineConfiguration().getIdentityService();
User user = identityService.createUserQuery().userId(assignee).singleResult();
if (user != null) {
// Get Email Address from User Profile
String recipient = user.getEmail();
if (recipient != null && !recipient.isEmpty()) {
Email email = new SimpleEmail();
email.setSmtpPort(587);
email.setSSL(true);
email.setTLS(true);
email.setCharset("utf-8");
email.setHostName(HOST);
email.setAuthentication(USER, PWD);
try {
email.setFrom("noreply#camunda.org");
email.setSubject("Task assigned: " + delegateTask.getName());
email.setMsg("Please complete: http://localhost:8080/camunda/app/tasklist/default/#/task/" + taskId);
email.addTo(recipient);
email.send();
LOGGER.info("Task Assignment Email successfully sent to user '" + assignee + "' with address '" + recipient + "'.");
} catch (Exception e) {
LOGGER.log(Level.WARNING, "Could not send email to assignee", e);
}
} else {
LOGGER.warning("Not sending email to user " + assignee + "', user has no email address.");
}
} else {
LOGGER.warning("Not sending email to user " + assignee + "', user is not enrolled with identity service.");
}
}
}
}
But it does not work. any ideas why?

Is the JAX-WS needs special dependency for insert spring #autowired

wrote a JAX-WS web service for my project.I use #autowired for inject a class...Then the web service returns null pointer exception... I went to the debug mode and verify the null pointer gives in the #autowired cord... Is the special annotation need for use #autowired in JAX-RS..
This is my Web Service class
package lk.slsi.webService;
import java.util.List;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.ws.rs.PathParam;
import lk.slsi.domain.CustomsPermit;
import lk.slsi.services.permitServices;
import org.springframework.beans.factory.annotation.Autowired;
#WebService(serviceName = "customsPermit",name = "permitRelease",portName = "nswPort",targetNamespace = "https://nationalsinglewindow.gov.lk/SLSIonNationalSingleWindow/")
#SOAPBinding(style = SOAPBinding.Style.DOCUMENT)
public class webServiceforCustoms {
#Autowired
private permitServices permitServices;
#WebMethod
public List<CustomsPermit> getXmlbyDate(#WebParam(name = "123") String dtIssue) {
List<CustomsPermit> permitRelease = permitServices.getPermitByDate(dtIssue);
return permitRelease;
}
#WebMethod
public CustomsPermit getXmlbyEntryNo(String SNumber) {
CustomsPermit permitRelease = permitServices.getPermitBySNumber(SNumber);
return permitRelease;
}
#WebMethod
public List<CustomsPermit> getXmlbyVATNo(String importerVAT) {
List<CustomsPermit> permitRelease = permitServices.getPermitByImporterVAT(importerVAT);
return permitRelease;
}
}
This is my service class
package lk.slsi.services;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
import javax.validation.Valid;
import java.util.List;
import javax.inject.Inject;
import lk.slsi.domain.CustomsPermit;
import lk.slsi.repository.PermitRepository;
import lk.slsi.security.domain.AuthenticatedUser;
import org.springframework.security.core.context.SecurityContextHolder;
#Service
#Scope("session")
public class permitServices{
private static final Logger serviceLogger = LogManager.getLogger(permitServices.class);
#Autowired
private PermitRepository permitRepository;
public boolean registerPermit(#Valid CustomsPermit customsPermit) {
serviceLogger.info("Starting to register new Agent. agent : [{}]", customsPermit);
try {
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
long userId = 0;
String agency = "";
String units = "";
List<String> roles;
if (principal != null && principal instanceof AuthenticatedUser) {
AuthenticatedUser auth = (AuthenticatedUser) principal;
userId = auth.getUserId();
agency = auth.getAgency();
roles = auth.getUserRoles();
String pattern = "yyyy-MM-dd HH:mm:ss";
String pattern2 = "yyyy-MM-dd";
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern);
SimpleDateFormat simpleDateFormat2 = new SimpleDateFormat(pattern2);
String date = simpleDateFormat.format(new Date());
String date2 = simpleDateFormat2.format(new Date());
String userandTime = "UserID " + Long.toString(userId) + " in " + date;
customsPermit.setAppPostdate(userandTime);
customsPermit.setUserID(Long.toString(userId));
customsPermit.setDtIssue(date2);
permitRepository.save(customsPermit);
serviceLogger.info("Successfully saved the agent in db");
return true;
}
} catch (Exception e) {
serviceLogger.error("Error occurred while registering agent. [{}]", e);
}
return false;
}
public CustomsPermit getFromId(Long id) {
serviceLogger.info("Fetching the agent by nic number : [{}]", id);
try {
return permitRepository.getFromId(id);
} catch (Exception e) {
serviceLogger.error("Error while retrieving the permit for id number [{}], [{}]", id, e);
return null;
}
}
public List<CustomsPermit> findAll() {
serviceLogger.info("Fetching Permit List");
return permitRepository.findAll();
}
public List<CustomsPermit> getPermitByImporterVAT(String importerVAT) {
serviceLogger.info("Fetching Permit List");
return permitRepository.getPermitByImporterVAT(importerVAT);
}
public List<CustomsPermit> getPermitByDate(String dtIssue) {
serviceLogger.info("Fetching Permit List");
return permitRepository.getPermitByDate(dtIssue);
}
public CustomsPermit getPermitBySNumber(String SNumber) {
return permitRepository.getPermitBySNumber(SNumber);
}
}
This is my repository class
package lk.slsi.repository;
import lk.slsi.domain.Agent;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.query.Param;
import java.util.List;
import lk.slsi.domain.CustomsPermit;
public interface PermitRepository extends CrudRepository<CustomsPermit, Long> {
#Override
CustomsPermit save(CustomsPermit customsPermit);
#Override
CustomsPermit findOne(Long id);
#Override
List<CustomsPermit> findAll();
#Query("select a from CustomsPermit a where a.id = :id")
CustomsPermit getFromId(#Param("id") Long id);
#Query("select a from CustomsPermit a where a.SNumber = :SNumber")
CustomsPermit getPermitBySNumber(#Param("SNumber") String SNumber);
#Query("select a from CustomsPermit a where a.importerVAT = :importerVAT")
List<CustomsPermit> getPermitByImporterVAT(#Param("importerVAT") String importerVAT);
#Query("select a from CustomsPermit a where a.dtIssue = :dtIssue")
List<CustomsPermit> getPermitByDate(#Param("dtIssue") String dtIssue);
}
This is my POM.XML
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>lk.slsi</groupId>
<artifactId>SLSIonNationalSingleWindow</artifactId>
<packaging>war</packaging>
<version>slsi-1.1.0-SNAPSHOT</version>
<name>SLSIonNationalSingleWindow Maven Webapp</name>
<url>http://maven.apache.org</url>
<scm>
<connection>scm:git:git#bitbucket.org:mof_SriLanka/SLSIonNationalSingleWindow.git</connection>
<url>scm:git:git#bitbucket.org:mof_SriLanka/SLSIonNationalSingleWindow.git</url>
<developerConnection>scm:git:git#bitbucket.org:mof_SriLanka/SLSIonNationalSingleWindow.git</developerConnection>
<tag>1.0.0</tag>
</scm>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.1.RELEASE</version>
</parent>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<sonar.exclusions>**/public/**/*</sonar.exclusions>
</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-tomcat</artifactId>-->
<!--<scope>provided</scope>-->
<!--</dependency>-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-taglibs</artifactId>
</dependency>
<!--handle servlet-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
<!--<Email Dependency>-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
<version>1.4.3.RELEASE</version>
</dependency>
<!--Add mysql dependency-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>6.0.3</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
</dependency>
<!--jasper-->
<dependency>
<groupId>net.sf.jasperreports</groupId>
<artifactId>jasperreports</artifactId>
<version>3.7.6</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.1</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.1</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.mail</groupId>
<artifactId>javax.mail-api</artifactId>
<version>1.5.5</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.bundles</groupId>
<artifactId>jaxrs-ri</artifactId>
<version>2.25</version>
</dependency>
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
<version>2.0.1</version>
<type>jar</type>
</dependency>
<!-- https://mvnrepository.com/artifact/org.glassfish.jersey.media/jersey-media-moxy -->
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-moxy</artifactId>
<version>2.25</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.glassfish.jersey.ext/jersey-spring3 -->
<dependency>
<groupId>org.glassfish.jersey.ext</groupId>
<artifactId>jersey-spring4</artifactId>
<version>2.26</version>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib-nodep</artifactId>
<version>2.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.sun.xml.ws/jaxws-ri-bom-ext -->
<dependency>
<groupId>com.sun.xml.ws</groupId>
<artifactId>jaxws-ri-bom-ext</artifactId>
<version>2.2.10</version>
<type>pom</type>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.xml.ws/jaxws-api -->
<dependency>
<groupId>javax.xml.ws</groupId>
<artifactId>jaxws-api</artifactId>
<version>2.2.10</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.glassfish.jersey.bundles.repackaged/jersey-guava -->
<dependency>
<groupId>org.glassfish.jersey.bundles.repackaged</groupId>
<artifactId>jersey-guava</artifactId>
<version>2.26-b03</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.activation/activation -->
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1</version>
</dependency>
<dependency>
<groupId>org.glassfish.metro</groupId>
<artifactId>webservices-rt</artifactId>
<version>2.3</version>
<scope>compile</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/com.github.jsr-330/core -->
<dependency>
<groupId>com.github.jsr-330</groupId>
<artifactId>core</artifactId>
<version>1.3.0</version>
</dependency>
<dependency>
<groupId>com.sun.xml.ws</groupId>
<artifactId>jaxws-rt</artifactId>
<version>2.2.8</version>
</dependency>
<dependency>
<groupId>org.jvnet.jax-ws-commons.spring</groupId>
<artifactId>jaxws-spring</artifactId>
<version>1.9</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</exclusion>
<exclusion>
<groupId>com.sun.xml.stream.buffer</groupId>
<artifactId>streambuffer</artifactId>
</exclusion>
<exclusion>
<groupId>org.jvnet.staxex</groupId>
<artifactId>stax-ex</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<finalName>SLSIonNationalSingleWindow</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<useSystemClassLoader>false</useSystemClassLoader>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-release-plugin</artifactId>
<version>2.5.2</version>
<configuration>
<tagNameFormat>#{project.version}</tagNameFormat>
<autoVersionSubmodules>true</autoVersionSubmodules>
</configuration>
</plugin>
</plugins>
</build>
</project>
This is my configuration class
package lk.slsi;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.support.SpringBootServletInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ImportResource;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import javax.annotation.PreDestroy;
/**
* Created by ignotus on 1/22/2017.
*/
#SpringBootApplication
#ComponentScan(basePackages = "lk.slsi")
#EnableWebMvc
#ImportResource(locations = "classpath:slsi-servlet-config.xml")
public class SLSIStarter extends SpringBootServletInitializer {
private static final Logger slsiLogger = LogManager.getLogger(SLSIStarter.class);
private static ConfigurableApplicationContext context;
public static void main(String[] args) {
slsiLogger.info("Starting application");
SpringApplication application = new SpringApplication(SLSIStarter.class);
context = application.run(args);
application.setRegisterShutdownHook(true);
}
#PreDestroy
private static void closeAppContext(){
context.close();
}
#Override
protected final SpringApplicationBuilder configure(final SpringApplicationBuilder application) {
return application.sources(SLSIStarter.class);
}
}
What is the error in my cord.
Create another class like this
#Service
public class PermitRepositoryImpl implements PermitRepository {
#Override
CustomsPermit save(CustomsPermit customsPermit){
//implement the code, returning null for now
return null;
}
#Override
CustomsPermit findOne(Long id){
//implement the code, returning null for now
return null;
}
#Override
List<CustomsPermit> findAll(){
//implement the code, returning null for now
return null;
}
#Query("select a from CustomsPermit a where a.id = :id")
CustomsPermit getFromId(#Param("id") Long id){
//implement the code, returning null for now
return null;
}
#Query("select a from CustomsPermit a where a.SNumber = :SNumber")
CustomsPermit getPermitBySNumber(#Param("SNumber") String SNumber){
//implement the code, returning null for now
return null;
}
#Query("select a from CustomsPermit a where a.importerVAT = :importerVAT")
List<CustomsPermit> getPermitByImporterVAT(#Param("importerVAT") String importerVAT){
//implement the code, returning null for now
return null;
}
#Query("select a from CustomsPermit a where a.dtIssue = :dtIssue")
List<CustomsPermit> getPermitByDate(#Param("dtIssue") String dtIssue){
//implement the code, returning null for now
return null;
}
}
Adding this class should solve your issue.

Arquillian API REST Example

I cannot found any example for jax-rs testing with arquillian. I use a wildfly 10 managed container.
I am trying to do it by my own, this is my sample code:
#RunWith(Arquillian.class)
public class DeploymentTest {
#Deployment(testable = false)
public static Archive<?> deploy() {
return ShrinkWrap.create(WebArchive.class, "cos-arq-test.war")
.addClasses(MANUEJB.class, HelloWorld.class, HelloWorldRESTImpl.class)
.addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml");
}
#ArquillianResource
private URL base;
private static WebTarget target;
#Before
public void setUpClass() throws MalformedURLException {
Client client = ClientBuilder.newClient();
target = client.target(URI.create(new URL(base, "rest/helloWorldREST").toExternalForm()));
}
#Test
#RunAsClient
public void testResponse(#ArquillianResource URL base) throws InterruptedException, ExecutionException {
System.out.println("====================================================");
System.out.println("This test should run inside the Wildfly 10 container");
System.out.println("====================================================");
try {
System.out.println("URL TARGET: " + target.getUri().toURL().toString());
} catch (MalformedURLException e) {
e.printStackTrace();
}
assertEquals("Hello", target.request().get().readEntity(String.class));
/*
Future<Response> r1 = target.request().async().get();
Response response = r1.get();
if (null != response) {
assertEquals(HttpStatus.OK, response.getStatus());
assertNotNull(response.getEntity());
assertEquals("Hello " + "manuel" + "!", response.readEntity(String.class));
}
*/
}
}
And this is my service code:
#Path("/helloWorldREST")
public class HelloWorldRESTImpl implements HelloWorld {
#GET
public Response sayHi() {
return Response.ok("Hello").build();
}
#Override
#GET
#Path("/sayHi/{name}")
#Produces(MediaType.APPLICATION_JSON)
public Response sayHi(#PathParam("name") String name) {
MANUEJB ejb = null;
javax.naming.Context initialContext = null;
try {
initialContext = new InitialContext();
} catch (NamingException e) {
e.printStackTrace();
}
try {
ejb = (MANUEJB) initialContext.lookup("java:app/cos-arq-test/MANUEJB");
} catch (NamingException e) {
e.printStackTrace();
}
String result = ejb.method(name);
return Response.ok(result).build();
}
}
But I get an error, and it does not find the service.
I use arquillian libraries with a managed wildfly 10 container:
<dependency>
<groupId>org.jboss.arquillian</groupId>
<artifactId>arquillian-bom</artifactId>
<version>1.1.11.Final</version>
<scope>import</scope>
<type>pom</type>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>org.jboss.arquillian.junit</groupId>
<artifactId>arquillian-junit-container</artifactId>
</dependency>
<dependency>
<groupId>org.wildfly.arquillian</groupId>
<artifactId>wildfly-arquillian-container-managed</artifactId>
<version>2.0.0.Final</version>
</dependency>
And this is my arquillian config for the container:
<arquillian xmlns="http://jboss.org/schema/arquillian"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://jboss.org/schema/arquillian http://jboss.org/schema/arquillian/arquillian_1_0.xsd">
<container qualifier="wildfly10" default="true">
<configuration>
<property name="jbossHome">/home/manumg/test-containers/wildfly-10.1.0.Final</property>
</configuration>
</container>
For a starter example, you can see https://github.com/arquillian/arquillian-extension-rest/blob/master/rest-client/README.md.
The code described in the readme is in the same repository at https://github.com/arquillian/arquillian-extension-rest/tree/master/rest-client/test-app.
For a starter maven project, I suggest you using the maven archetype wildfly-jakartaee-webapp-archetype, related to Wildfly 21 (jakarta ee 8 container).
To run the test you have to:
Activate the profile arq-managed
Download Wildfly 21 (from https://www.wildfly.org/downloads/)
Define the JBOSS_HOME variable (pointing to the local Wildfly directory)

#ModelAttribute controller spring-mvc mocking

I want to test a controller which is using #ModelAttribute for one of its method arguments.
public String processSaveAction(#ModelAttribute("exampleEntity") ExampleEntity exampleEntity)
#ModelAttribute method getExampleEntity is using #RequestParam:
#ModelAttribute("exampleEntity")
public ExampleEntity getExampleEntity(#RequestParam(value = "id", required = true) ExampleEntity exampleEntity) {
My controller is using WebDataBinder to call a factory, which returns an object based on param "id".
#Controller
public class ExampleController(){
#Autowired private IdEditorFactory idEditorFactory;
#InitBinder
public void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(ExampleEntity.class, idEditorFactory.createEditor(ExampleEntity.class));
}
#ModelAttribute("exampleEntity")
public ExampleEntity getExampleEntity(#RequestParam(value = "id", required = true) ExampleEntity exampleEntity) {
//Irrelevant operations
return exampleEntity;
}
#RequestMapping(method = RequestMethod.POST, params = "action=save")
public String processSaveAction(
#RequestParam(value = "confirmed") String exampleString,
#ModelAttribute("exampleEntity") ExampleEntity exampleEntity,
BindingResult result, HttpServletRequest request)
throws IOException {
boolean success = editorProcessor.processSaveAction(exampleString,
exampleEntity, result, request);
return success ? getSuccessView(exampleEntity) : VIEW_NAME;
}
}
And my test:
#WebAppConfiguration
public class ExampleControllerTest{
#Mock private EditorProcessor editorProcessor;
#Mock private IdEditorFactory idEditorFactory;
#InjectMocks private ExampleController exampleController;
private MockMvc mockMvc;
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mockMvc = MockMvcBuilders.standaloneSetup(exampleController).build();
WebDataBinder webDataBinder = new WebDataBinder(ExampleEntity.class);
webDataBinder.registerCustomEditor(ExampleEntity.class, idEditorFactory.createEditor(ExampleEntity.class));
}
#Test
public void shouldProcessSaveAction() throws Exception {
// given
BindingResult result = mock(BindingResult.class);
ExampleEntity exampleEntity = mock(ExampleEntity.class);
HttpServletRequest httpServletRequest = mock(HttpServletRequest.class);
given(editorProcessor.processSaveAction("confirmed", exampleEntity, result, httpServletRequest)).willReturn(true);
// when
ResultActions perform = mockMvc.perform(post("/").sessionAttr("exampleEntity", exampleEntity)
.param("id", "123456"
.param("action","save"));
// then
perform.andDo(print())
.andExpect(status().isOk());
}
}
I want to somehow mock getExampleEntity() so that every time I perform a POST with parameter "id", I receive a mocked object ("exampleEntity") for the test.
I could introduce #Binding to the test, but then I would have to mock many levels of methods (like initBinder -> idEditoryFactory-> editor -> hibernateTemplate and so on) only to get an entity from some source (for example, a database).
You can pass in the required #ModelAttribute object with the .flashAttr() method like so:
mockMvc.perform(post("/")
.param("id", "123456")
.param("action","save")
.flashAttr("exampleEntity", new ExampleEntity()));
First, test code shouldn't change our development code. #ModelAttribute will be mount from your param attribute, so .param() is enough. Below is my demo:
#Test
public void registerUser() throws Exception {
System.out.println("hello......." + rob.toString());
RequestBuilder request = post("/register.html")
.param("username", rob.getUsername())
.param("password", rob.getPassword())
.param("firstName", rob.getFirstName())
.param("lastName", rob.getLastName())
.param("email", rob.getEmail())
.with(csrf());
mvc
.perform(request)
.andDo(MockMvcResultHandlers.print())
.andExpect(redirectedUrl("/"));
}
Then is my #Controller:
#Controller
public class LoginController {
#Autowired
private UserService userService;
#RequestMapping(value = "/remove", method = RequestMethod.GET)
public String removeById(#RequestParam("userid") int id, RedirectAttributes attr) {
attr.addFlashAttribute("message", "remove!!!");
attr.addAttribute("mess", "remove ");
return "redirect:/userlist.html";
}
#RequestMapping(value = "/register", method = RequestMethod.POST)
public String register(#ModelAttribute("user") User user, ModelMap model) {
System.out.println("register " + user.toString());
boolean result = userService.add(user);
model.addAttribute("message", "add " + (result ? "successed" : "failed") + "!!!");
return "/";
}
}
This can submit the right user object to the public String register(#ModelAttribute("user") User user, ModelMap model).
I'm new to Spring MVC, and currently writing a #Controller class but none of the methods have business logic, let alone HTML files for the views under'/static/'. First, I wanted to see how I can Unit Test every method to make sure all end points responded 200/ok before I inserted the business logic, you know Test Driven Development. Then I had difficulty when unit testing #PostMapping annotation method that had a #ModelAttribute assigned to it. After my whole search yesterday, I put together code for someone to unit test such cases involving #PostMapping and #ModelAttribute where you need to update the parameter values of your model attribute on the 'post' method. I'm more than welcome positive feedback to make my tests better, just wanted to post this in cases someone else that's also new wanted to test and make sure that the new info will be saved after the post in the #ModelAttribute without needing a html/jsp file for views for standalone unit testing, look at #Controller2 and String updateQuoteRequest() method for reference, and the last test in class QuoteRequestManagementController_UnitTests for more details.
pom.xml file:
<?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.2.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>spring-mvc-hotel-app</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>serving-web-content</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-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<!-- Spring Boot Test Starter is Starter for testing Spring Boot applications
with libraries including JUnit, Hamcrest and Mockito. -->
<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>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Model Attribute Class:
package com.corplithotel.eventsapp.domain;
//Create the Model Attribute class, and its class members
public class QuoteRequest {
String customer;
String age;
String budget;
String eventType;
String foodAllergies;
//getters and setters
public String getCustomer() {
return customer;
}
public void setCustomer(String customer) {
this.customer = customer;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
public String getBudget() {
return budget;
}
public void setBudget(String budget) {
this.budget = budget;
}
public String getEventType() {
return eventType;
}
public void setEventType(String eventType) {
this.eventType = eventType;
}
public String getFoodAllergies() {
return foodAllergies;
}
public void setFoodAllergies(String foodAllergies) {
this.foodAllergies = foodAllergies;
}
}
Main Class:
package com.corplithotel.eventsapp;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class CorpLitHotel {
public static void main(String[] args) {
SpringApplication.run(CorpLitHotel.class, args);
}
}
#Controller1
package com.corplithotel.eventsapp.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import com.corplithotel.eventsapp.domain.QuoteRequest;
//Step 1: * Create QuoteRequestController *
/*#Conroller annotation makes this class a controller, next we need to
* add 'handler mappings' to provide the controller some functionality.
* For Step 1, we won't add logic for #RequestMapping 'beginQuoteRequest()'
* & #Postrequest 'submitQuoteRequest()' methods, we will Mock the class
* and unit test in Step 2 for TDD examples:
*
*
*/
#Controller
public class QuoteRequestController {
/*#GetMapping annotation is a 'handler mapping' annotation.
* When a user comes to the page to fill out the Quote form, they
* first need to get the page. The return of the method will be a
* 'logical view name', which is just a string, and tends to correlate
* to some HTML, JSP or whatever file you're using for your View.
*
*/
#GetMapping("/newquote")
public String beginQuoteRequest(Model model) {
//Check Unit Test for logic
return "newQuote";
}//beginQuoteRequest()
/*#PosMapping annotation is another 'handler mapping' annotation.
* Once a user fills out the Quote form with their name and
* other event details, they may want to save or post that quote.
* We need to add a handler for the Post, and needs to be a separate
* method. Will be a separate page with a confirmation message to let
* the user know their Quote request has been received.
*/
#PostMapping("/newquote")
public String submitQuoteRequest(#ModelAttribute QuoteRequest formBean) {
//Check Unit Test for ideal logic
return "newQuoteConfirmation";
}//submitQuoteRequest()
}
Controller 1 Unit Tests:
package com.corplithotel.eventsapp.controller;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.api.TestInstance.Lifecycle;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import com.corplithotel.eventsapp.domain.QuoteRequest;
/*Step 2 *Create Unit tests for QuoteRequestController*:
* this tests are assuming
*/
#ExtendWith(MockitoExtension.class)
#WebMvcTest( QuoteRequestController.class)
#TestInstance(Lifecycle.PER_CLASS)
public class QuoteRequestController_UnitTests {
#Mock
private WebApplicationContext wac;
#InjectMocks
private QuoteRequestController qrc;
private MockMvc qrcMockMvc;
#BeforeAll
public void setUp() {
qrcMockMvc = MockMvcBuilders.standaloneSetup(qrc).build();
}//BeforeAll
#Test
#DisplayName("testGetQuoteForm.. beginQuoteRequest().. Expected to pass..")
public void testGetQuoteForm() throws Exception {
//simulate getting a new form for the user to fill in (GET)
qrcMockMvc
.perform(get("/newquote"))
.andExpect(status().is(200))
.andReturn();
}//testGetQuoteForm()
#Test
#DisplayName("testPostQuoteForm().. submitQuoteRequest.. Expected to pass..")
public void testPostQuoteForm() throws Exception {
QuoteRequest aFormBean = new QuoteRequest();
qrcMockMvc
.perform(post("/newquote", aFormBean))
.andExpect(status().isOk())
.andReturn();
}//testGetQuoteForm()
}// QuoteRequestController_UnitTests
Result 1:
Junit Controller 1 Results
Controller 2:
package com.corplithotel.eventsapp.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import com.corplithotel.eventsapp.domain.QuoteRequest;
/*Step 3 *Creating QuoteRequestManagementController
* This is the controller that the sales team member
* uses to reply to a customer's request for an estimate.
* Sale's Team member can see all the incoming requests.
*
*Controller method's body for Step 3 will be empty, we will unit test
* every method of the Controller first in Step 4.
*/
#Controller
public class QuoteRequestManagementController {
/*
* We will be specifying, parameters, look for a parameter of
* a particular value; or looking for the absence of a parameter
*/
//Specifying: Sale's Team member can see all the incoming requests.
#GetMapping(path = "/quoteRequests")
public String listQuoteRequests() {
return "quoteRequestsList";
}//listRequests()
/*Parameter Of A Specific Value: Narrow down search for different
* types of sales reps. Look for 'eventType' = 'wedding' for sales reps that
* only deal with weddings and only see events associated
* with weddings.
*/
#GetMapping(path = "/quoteRequests", params="eventType=wedding")
public String listWeddingRequests() {
return "quoteWeddingRequestsList";
}//listWeddingRequests()
/*Parameter Of A Specific Value: Narrow down search for different types of sales
reps.
* Look for 'eventType' = 'birthday' for sales reps that
* only deal with weddings and only see events associated
* with weddings.
*/
#GetMapping(path = "/quoteRequests", params="eventType=birthday")
public String listBirthdayRequests() {
return "quoteBirthdayRequestsList";
}//listBirthdayRequests()
/*
* Look for 'eventType' parameter regardless of its value
*/
#GetMapping(path = "/quoteRequests", params="eventType")
public String listAllEventTypeRequests() {
return "quoteAllEventTypeRequestList";
}//listAllEventTypeRequests()
/*
* Absence of a parameter: Look for requests with no 'eventType' parameter
*/
#GetMapping(path = "/quoteRequests", params="!eventType")
public String listNoneEventTypeRequests() {
return "quoteNoneEventTypeRequestsList";
}//listNoneEventTypeRequests()
/*
* Specifying: Create another mapping for a sales rep to drill down
* from what I see in a list and pick one particular quote
* request. We will accomplish this by providing each
* quote request a unique quoteID using #PathVariable
*/
#GetMapping("/quoteRequests/{quoteID}")
public String viewQuoteRequest(#PathVariable int quoteID) {
//refer to quoteID in my implementation
return "quoteRequestsDetails";
}//viewQuoteRequest()
/*
*For this scenario lets say a sales rep is in a particular
* quote and maybe want to add a note, which will require them
* to save the content of the screen. This means we need a
* #PostMapping. The sales rep might want to update the customer
* name, event type, food allergy side note, etc.
*
*Once they hit 'save', all the data will come in and be accessible
* through #ModelAttribute and we can reference the Model Attribute in
* the method signature. So as we implement the logic in the controller
* we get to use a Model Bean and pull in all the updated data
* and ultimately save the data somewhere.
*/
#PostMapping ("/quoteUpdateDetails")
public String updateQuoteRequest(
#ModelAttribute("quoteRequest") QuoteRequest quoteRequest) {
//implement a save of all the form bean information
return "quoteUpdateDetails";
}//updateQuoteRequest()
}
Controller 2 Unit Test:
package com.corplithotel.eventsapp.controller;
import static
org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static
org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static
org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.api.TestInstance.Lifecycle;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.test.web.servlet.MockMvc;
import
org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import com.corplithotel.eventsapp.domain.QuoteRequest;
#ExtendWith(MockitoExtension.class)
#WebMvcTest( QuoteRequestManagementController.class)
#TestInstance(Lifecycle.PER_CLASS)
class QuoteRequestManagementController_UnitTests {
#Mock
private WebApplicationContext wac;
#InjectMocks
private QuoteRequestManagementController qrmc;
private MockMvc qrmcMockMvc;
#BeforeAll
public void setUp() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix("/WEB-INF/");
viewResolver.setSuffix(".html");
qrmcMockMvc=
MockMvcBuilders.standaloneSetup(qrmc)
.setViewResolvers(viewResolver).build();
}//BeforeAll
#Test
#DisplayName("testListQuoteRequests().. Test should pass")
void testlistQuoteRequests() throws Exception {
qrmcMockMvc
.perform(get("/quoteRequests"))
.andExpect(status().is(200))
.andReturn();
}//testlistRequests()
#Test
#DisplayName("testListWeddingRequests() .. Parameter Of A Specific Value Test1.. Test should pass")
void testlistWeddingRequests() throws Exception {
qrmcMockMvc
.perform(get("/quoteRequests?eventType=wedding"))
.andExpect(status().is(200))
.andReturn();
}//testlistWeddingRequests()
#Test
#DisplayName("testListBirthdayRequests() .. Parameter Of A Specific Value Test2.. Test should pass")
void testlistBirthdayRequests() throws Exception {
qrmcMockMvc
.perform(get("/quoteRequests?eventType=birthday"))
.andExpect(status().is(200))
.andReturn();
}//testlistBirthdayRequests()
#Test
#DisplayName("testListAllEventsRequests() .. Parameter with no specified value.. Test should pass")
void testlistAllEventsRequests() throws Exception {
qrmcMockMvc
.perform(get("/quoteRequests?eventType"))
.andExpect(status().is(200))
.andReturn();
}//testlistBirthdayRequests()
#Test
#DisplayName("testNoneEventTypeRequests() .. no parameter .. Test should pass")
void testNoneEventTypeRequests() throws Exception {
qrmcMockMvc
.perform(get("/quoteRequests?!eventType"))
.andExpect(status().is(200))
.andReturn();
}//testlistBirthdayRequests()
#Test
#DisplayName("testViewQuoteRequest().. by 'quoteID'.. Test should pass")
void testViewQuoteRequest() throws Exception {
qrmcMockMvc
.perform(get("/quoteRequests/{quoteID}", 4))
.andExpect(status().is(200))
.andReturn();
}//testViewQuoteRequest()
#Test
#DisplayName("test2ViewQuoteRequest().. by 'quoteID'.. Test should pass")
void tes2tViewQuoteRequest() throws Exception {
qrmcMockMvc
.perform(get("/quoteRequests/{quoteID}", 415))
.andExpect(status().is(200))
.andReturn();
}//testViewQuoteRequest()
#Test
void testupdateQuoteRequest() throws Exception {
MockHttpServletRequestBuilder updateDetails = post("/quoteUpdateDetails")
.param("customer", "Joe")
.param("age", "12")
.param("budget", "$1209")
.param("eventType", "wedding")
.param("foodAllergies", "fish")
.flashAttr("quoteRequest", new QuoteRequest());
qrmcMockMvc
.perform( updateDetails)
.andExpect(status().is(200));
}
}

Endpoint Publish for REST Web Services

I've published JAX-WS web services with Endpoint.publish during development. Is there any such utility class exists (in JAX-RS) for publishing REST web services in jersey? I referred couple of articles, and majority of them are based on publishing the web services in some containers like Jetty, Grizzly etc.
Jersey-Grizzly has a very simple solution. From https://github.com/jesperfj/jax-rs-heroku:
package embedded.rest.server;
import java.util.HashMap;
import java.util.Map;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import com.sun.grizzly.http.SelectorThread;
import com.sun.jersey.api.container.grizzly.GrizzlyWebContainerFactory;
#Path("/hello")
public class Main {
public static void main(String[] args) {
final String baseUri = "http://localhost:7080/";
final Map<String, String> initParams = new HashMap<String, String>();
// Register the package that contains your javax.ws.rs-annotated beans here
initParams.put("com.sun.jersey.config.property.packages","embedded.rest.server");
System.out.println("Starting grizzly...");
try {
SelectorThread threadSelector =
GrizzlyWebContainerFactory.create(baseUri, initParams);
System.out.println(String.format("Jersey started with WADL "
+ "available at %sapplication.wadl.", baseUri));
}
catch(Exception e) {
e.printStackTrace();
}
}
#GET
#Produces(MediaType.TEXT_PLAIN)
public String hello() {
return "Well, this was easy!";
}
}
If you're using Maven, you'll need the following three dependencies:
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-grizzly</artifactId>
<version>1.15</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-bundle</artifactId>
<version>1.15</version>
</dependency>
<dependency>
<groupId>com.sun.grizzly</groupId>
<artifactId>grizzly-servlet-webserver</artifactId>
<version>1.9.18-i</version>
</dependency>
To test it, just open http://localhost:7080/hello in a browser.
I think you can use Provider interface to publishing a RESTful Web Service with JAX-WS.
The example class:
#WebServiceProvider
#BindingType(value=HTTPBinding.HTTP_BINDING)
public class AddNumbersImpl implements Provider {
#Resource
protected WebServiceContext wsContext;
public Source invoke(Source source) {
try {
MessageContext mc = wsContext.getMessageContext();
// check for a PATH_INFO request
String path = (String)mc.get(MessageContext.PATH_INFO);
if (path != null && path.contains("/num1") &&
path.contains("/num2")) {
return createResultSource(path);
}
String query = (String)mc.get(MessageContext.QUERY_STRING);
System.out.println("Query String = "+query);
ServletRequest req = (ServletRequest)mc.get(MessageContext.SERVLET_REQUEST);
int num1 = Integer.parseInt(req.getParameter("num1"));
int num2 = Integer.parseInt(req.getParameter("num2"));
return createResultSource(num1+num2);
} catch(Exception e) {
e.printStackTrace();
throw new HTTPException(500);
}
}
private Source createResultSource(String str) {
StringTokenizer st = new StringTokenizer(str, "=&/");
String token = st.nextToken();
int number1 = Integer.parseInt(st.nextToken());
st.nextToken();
int number2 = Integer.parseInt(st.nextToken());
int sum = number1+number2;
return createResultSource(sum);
}
private Source createResultSource(int sum) {
String body =
"<ns:addNumbersResponse xmlns:ns="http://java.duke.org"><ns:return>"
+sum
+"</ns:return></ns:addNumbersResponse>";
Source source = new StreamSource(
new ByteArrayInputStream(body.getBytes()));
return source;
}
}
To deploy our endpoint on a servlet container running with the JAX-WS
RI we need to create a WAR file.
The adjusted web.xml:
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee">
<listener>
<listener-class>com.sun.xml.ws.transport.http.servlet.WSServletContextListener
</listener>
<servlet>
<servlet-name>restful-addnumbers</servlet-name>
<servlet-class>com.sun.xml.ws.transport.http.servlet.WSServlet
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>restful-addnumbers</servlet-name>
<url-pattern>/addnumbers/*</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>60</session-timeout>
</session-config>
</web-app>
and need to add sun-jaxws.xml deployment descriptor to the WAR file.
<endpoints
xmlns="http://java.sun.com/xml/ns/jax-ws/ri/runtime"
version="2.0">
<endpoint
name="restful-addnumbers"
implementation="restful.server.AddNumbersImpl"
wsdl="WEB-INF/wsdl/AddNumbers.wsdl"
url-pattern="/addnumbers/*" />
</endpoints>
Or could be create simple HttpServer
import java.io.IOException;
import com.sun.jersey.api.container.httpserver.HttpServerFactory;
import com.sun.net.httpserver.HttpServer;
public class YourREST {
static final String BASE_URI = "http://localhost:9999/yourrest/";
public static void main(String[] args) {
try {
HttpServer server = HttpServerFactory.create(BASE_URI);
server.start();
System.out.println("Press Enter to stop the server. ");
System.in.read();
server.stop(0);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}