RESTEasy Java 11, Tomcat 10.1 How to deploy an run - maven

Since days i'm googling for a working solution on how to deploy an run a RESTEasy JAX-RS test application.
It has to run on at least Java 11 and Tomcat 10.1 using the most actual JAX-RS and RESTEasy version.
Regardless what i'm trying getting it up and running, each URL call to - as example -
http://localhost:8080/NetworkManagement/network-management/configurations ends with error 404.
Please, could anyone give me a hint or solution for this?
The since the actual last try used code fragments are posted in the next posts - Eclipse 22.06 maven project:
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>
<parent>
<artifactId>ParentServer</artifactId>
<groupId>com.gncc.srv</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>api.rest</artifactId>
<packaging>war</packaging>
<name>GNCC Base Rest Api Server</name>
<!-- FIXME change it to the project's website -->
<url>http://localhost:8080</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<swagger-core-version>2.0.9</swagger-core-version>
<jackson-version>2.11.2</jackson-version>
<jetty-version>9.2.9.v20150224</jetty-version>
<resteasy-version>3.15.3.Final</resteasy-version>
<resteasy-servlet>6.2.2.FINAL</resteasy-servlet>
<slf4j-version>1.6.3</slf4j-version>
<junit-version>4.13.1</junit-version>
<servlet-api-version>4.0.4</servlet-api-version>
<jakarta-annotation-version>1.3.5</jakarta-annotation-version>
<beanvalidation-version>2.0.2</beanvalidation-version>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jaxrs</artifactId>
<version>${resteasy-version}</version>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jaxb-provider</artifactId>
<version>${resteasy-version}</version>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-servlet-initializer</artifactId>
<version>${resteasy-servlet}</version>
</dependency>
</dependencies>
<build>
<finalName>NetworkManagement</finalName>
<pluginManagement>
<!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.2</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
web.xml
<?xml version="1.0" encoding="UTF-8"?><web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="https://jakarta.ee/xml/ns/jakartaee"
xmlns:web="http://xmlns.jcp.org/xml/ns/javaee"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd http://xmlns.jcp.org/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="WebApp_ID" version="5.0">
<display-name>Archetype Created Web Application</display-name>
</web-app>
App:
package com.gncc.srv.api.rest;
import java.util.HashSet;
import java.util.Set;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
import com.gncc.srv.api.rest.service.ConfigurationResource;
#ApplicationPath("/network-management")
public class NetworkManagement extends Application {
private Set<Object> singletons = new HashSet<Object>();
private Set<Class<?>> empty = new HashSet<Class<?>>();
public NetworkManagement() {
singletons.add(new ConfigurationResource());
}
#Override
public Set<Class<?>> getClasses() {
return empty;
}
#Override
public Set<Object> getSingletons() {
return singletons;
}}
resource.class
package com.gncc.srv.api.rest.service;
import java.util.List;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Link;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo;
import com.gncc.srv.api.rest.dao.ConfigurationDB;
import com.gncc.srv.api.rest.domain.Configuration;
import com.gncc.srv.api.rest.domain.Configurations;
import com.gncc.srv.api.rest.domain.common.Message;
import com.gncc.srv.api.rest.domain.common.Status;
/**
* This REST resource has common path "/configurations" and
* represents configurations collection resources
* as well as individual collection resources.
*
* Default MIME type for this resource is "application/XML"
* */
#Path("/configurations")
#Produces("application/xml")
public class ConfigurationResource
{
/**
* Initialize the application with these two default configurations
* */
static {
ConfigurationDB.createConfiguration("Some Content", Status.ACTIVE);
ConfigurationDB.createConfiguration("Some More Content", Status.INACTIVE);
}
/**
* Use uriInfo to get current context path and to build HATEOAS links
* */
#Context
UriInfo uriInfo;
/**
* Get configurations collection resource mapped at path "HTTP GET /configurations"
* */
#GET
public Configurations getConfigurations() {
List<Configuration> list = ConfigurationDB.getAllConfigurations();
Configurations configurations = new Configurations();
configurations.setConfigurations(list);
configurations.setSize(list.size());
//Set link for primary collection
Link link = Link.fromUri(uriInfo.getPath()).rel("uri").build();
configurations.setLink(link);
//Set links in configuration items
for(Configuration c: list){
Link lnk = Link.fromUri(uriInfo.getPath() + "/" + c.getId()).rel("self").build();
c.setLink(lnk);
}
return configurations;
}
/**
* Get individual configuration resource mapped at path "HTTP GET /configurations/{id}"
* */
#GET
#Path("/{id}")
public Response getConfigurationById(#PathParam("id") Integer id){
Configuration config = ConfigurationDB.getConfiguration(id);
if(config == null) {
return Response.status(javax.ws.rs.core.Response.Status.NOT_FOUND)
.build();
}
if(config != null){
UriBuilder builder = UriBuilder.fromResource(ConfigurationResource.class)
.path(ConfigurationResource.class, "getConfigurationById");
Link link = Link.fromUri(builder.build(id))
.rel("self")
.build();
config.setLink(link);
}
return Response.status(javax.ws.rs.core.Response.Status.OK)
.entity(config)
.build();
}
/**
* Create NEW configuration resource in configurations collection resource
* */
#POST
#Path("/")
#Consumes("application/xml")
public Response createConfiguration(Configuration config){
if(config.getContent() == null) {
return Response.status(javax.ws.rs.core.Response.Status.BAD_REQUEST)
.entity(new Message("Config content not found"))
.build();
}
Integer id = ConfigurationDB.createConfiguration(config.getContent(), config.getStatus());
Link lnk = Link.fromUri(uriInfo.getPath() + "/" + id).rel("self")
.build();
return Response.status(javax.ws.rs.core.Response.Status.CREATED)
.location(lnk.getUri())
.build();
}
/**
* Modify EXISTING configuration resource by it’s "id" at path "/configurations/{id}"
* */
#PUT
#Path("/{id}")
#Consumes("application/xml")
public Response updateConfiguration(#PathParam("id") Integer id, Configuration config){
Configuration origConfig = ConfigurationDB.getConfiguration(id);
if(origConfig == null) {
return Response.status(javax.ws.rs.core.Response.Status.NOT_FOUND)
.build();
}
if(config.getContent() == null) {
return Response.status(javax.ws.rs.core.Response.Status.BAD_REQUEST)
.entity(new Message("Config content not found"))
.build();
}
ConfigurationDB.updateConfiguration(id, config);
return Response.status(javax.ws.rs.core.Response.Status.OK)
.entity(new Message("Config Updated Successfully"))
.build();
}
/**
* Delete configuration resource by it’s "id" at path "/configurations/{id}"
* */
#DELETE
#Path("/{id}")
public Response deleteConfiguration(#PathParam("id") Integer id){
Configuration origConfig = ConfigurationDB.getConfiguration(id);
if(origConfig == null) {
return Response.status(javax.ws.rs.core.Response.Status.NOT_FOUND).build();
}
ConfigurationDB.removeConfiguration(id);
return Response.status(javax.ws.rs.core.Response.Status.OK).build();
}
}

You're RESTEasy dependencies do not look correct. You're mixing two different versions of RESTEasy which will not work. You need to use 6.2.2.Final if you're using Jakarta EE 9+, which Tomcat 10 uses. Your dependencies should look more like:
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-client</artifactId>
<version>${resteasy-version}</version>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-core</artifactId>
<version>${resteasy-version}</version>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jaxb-provider</artifactId>
<version>${resteasy-version}</version>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-servlet-initializer</artifactId>
<version>${resteasy-version}</version>
</dependency>

Related

Maven Junit 5, Cucumber not running tests

When executing my runner, or running my .feature file, no tests are ran via cucumber (same with mvn clean install, mvn clean test etc).
The rest of my program runs completely as expected, and this is an issue I've been gruelling with for a while now.
Result from IntelliJ IDE When I run my runner class :
Folder Structure:
My full pom is like so:
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>IE2ETest</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<junit-jupiter.version>5.7.2</junit-jupiter.version>
<maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version>
<cucumber.version>6.10.4</cucumber.version>
<selenium-jupiter.version>3.4.0</selenium-jupiter.version>
<java.version>1.8</java.version>
<maven.compiler.target>${java.version}</maven.compiler.target>
<maven.compiler.source>${java.version}</maven.compiler.source>
<project.enconding>UTF-8</project.enconding>
<project.build.sourceEncoding>${project.enconding}</project.build.sourceEncoding>
<project.reporting.outputEncoding>${project.enconding}</project.reporting.outputEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>${junit-jupiter.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-java</artifactId>
<version>${cucumber.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-junit-platform-engine</artifactId>
<version>${cucumber.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.github.bonigarcia</groupId>
<artifactId>selenium-jupiter</artifactId>
<version>${selenium-jupiter.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>5.7.0</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven-surefire-plugin.version}</version>
<configuration>
<properties>
<configurationParameters>
cucumber.plugin=pretty,html:target/site/cucumber-pretty.html
cucumber.publish.quiet=true
cucumber.publish.enabled=false
</configurationParameters>
</properties>
</configuration>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
</plugin>
</plugins>
</build>
RunnerTest.java:
package cucumberTests;
import io.cucumber.junit.platform.engine.Cucumber;
#Cucumber
public class RunnerTest {
}
StepDefinitions.java:
package cucumberTests.steps;
import helperpackage.Car;
import io.cucumber.java.en.And;
import io.cucumber.java.en.Given;
import io.cucumber.java.en.Then;
import io.cucumber.java.en.When;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import pomPages.CarTaxHomePage;
import pomPages.FreeCheckPage;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
public class StepDefinitions {
String drivePath = "./src/test/drivers/chromedriver.exe";
String currentUrl;
WebDriver driver;
CarTaxHomePage homePage;
FreeCheckPage freePage;
#Given("Valid Registration value of {string}")
public void checkReg(String reg){
assertTrue(Car.isValid(reg));
}
#When("the website {string} is live")
public void openSite(String url) throws IOException {
System.setProperty("webdriver.chrome.driver", drivePath);
driver = new ChromeDriver();
driver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);
driver.get("https://"+url+"/");
}
#And("user enters value of {string}")
public void enterText(String reg) throws InterruptedException {
homePage = new CarTaxHomePage(driver);
Thread.sleep(500);
homePage.editText(reg);
}
#And("user clicks on the free option")
public void clickSubmit(){
homePage.clickFreeCheck();
}
#Then("user should be taken to the {string} page")
public void checkPage(String url){
freePage = new FreeCheckPage(driver);
String currentUrl = driver.getCurrentUrl();
String regex = "^(https:\\/\\/"+url +"\\/)";
String x = "^(https:\\/\\/" + url + "?\\S+)";
if (!currentUrl.matches(regex)){
throw new IllegalArgumentException("Bad link");
};
}
#And("Number plate {string} Should appear")
public void checkResults(String plate, String make){
String plateReturned = freePage.getRegReturned();
String makeReturned = freePage.getMakeReturned();
if (plateReturned.equals(plateReturned) && makeReturned.equals(make)){
//
}else{
throw new IllegalArgumentException("Wrongfully returned");
}
}
}
My IDE Shows that these steps are referenced in another class, as Cucumber doesn't complain about finding the path to features, I'm currently at a loss.
StepDefinitions.feature
Feature: Check tax on car
Scenario : User enters a valid Reg number and clicks the free check option
Given Valid Registration value of "LT09YJJ"
When the website "check.co.uk" is live
And user enters value of "9YJJ"
And user clicks on the free option
Then user should be taken to the "taxcheck.co.uk/hello" page
And Number plate "9YJJ" Should appear
My Cucumber.properties
cucumber.publish.enabled=true

JDK 11 JavaFX with Maven: can't add dependencies to project

I used the sample archetype of openjfx to create a simple FXML base project from here: https://openjfx.io/openjfx-docs/#maven
I want to add other functionalities (such as parsing of xml files etc.) but when i try to use the added dependency, for some reason the objects are not recognized.
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>org.msd</groupId>
<artifactId>MSDLog</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>15.0.1</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-fxml</artifactId>
<version>15.0.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.dataformat/jackson-dataformat-xml -->
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
<version>2.12.2</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<release>11</release>
</configuration>
</plugin>
<plugin>
<groupId>org.openjfx</groupId>
<artifactId>javafx-maven-plugin</artifactId>
<version>0.0.5</version>
<configuration>
<mainClass>org.msd.App</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
App.java file:
You can see that the XmlMapper is commented out since it does not recognize it
package org.msd;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import java.io.File;
import java.io.IOException;
import java.util.Objects;
/**
* JavaFX App
*/
public class App extends Application {
private static Scene scene;
#Override
public void start(Stage stage) throws IOException {
scene = new Scene(loadFXML("environment"), 640, 480);
stage.setScene(scene);
stage.show();
}
static void setRoot(String fxml) throws IOException {
//------- THIS FAILS -------
XmlMapper xmlMapper = new XmlMapper();
scene.setRoot(loadFXML(fxml));
}
private static Parent loadFXML(String fxml) throws IOException {
FXMLLoader fxmlLoader = new FXMLLoader(App.class.getResource(fxml + ".fxml"));
return fxmlLoader.load();
}
public static void main(String[] args) {
launch();
}
}
Trying to import package:
Trying to "Add Maven dependency..." will suggest irrelevant packages
What am i missing???

Spring config for connecting to Postgres. Need bean: 'org.flywaydb.core.internal.jdbc.JdbcTemplate'

I'm getting this error when trying to run my Spring application.
Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2019-09-22 23:55:45.397 ERROR 36321 --- [ main] o.s.b.d.LoggingFailureAnalysisReporter :
***************************
APPLICATION FAILED TO START
***************************
Description:
Parameter 0 of constructor in com.example.demo.dao.UserDataAccessService required a bean of type 'org.flywaydb.core.internal.jdbc.JdbcTemplate' that could not be found.
Action:
Consider defining a bean of type 'org.flywaydb.core.internal.jdbc.JdbcTemplate' in your configuration.
The application works when I use my fakeUserData file. It seems like there is a dependency issue, but I've double checked and it looks like the dependencies are all there.
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 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.1.8.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo</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-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
application.yml
app:
datasource:
jdbc-url: jdbc:postgresql://localhost:5432/springbootpostgresdb
username: postgres
password: password
pool-size: 30
UserDataAccessService.java
package com.example.demo.dao;
import com.example.demo.model.User;
import org.flywaydb.core.internal.jdbc.JdbcTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import java.sql.SQLException;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
#Repository("postgresql")
public class UserDataAccessService implements Userdao {
private final JdbcTemplate jdbcTemplate;
#Autowired
public UserDataAccessService(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
#Override
public int insertUser(UUID id, User user) {
return 0;
}
#Override
public int deleteUserById(UUID id) {
return 0;
}
#Override
public int updateUserById(UUID id, User user) {
return 0;
}
#Override
public Optional<User> selectUserById(UUID id) {
return Optional.empty();
}
#Override
public List<User> selectAllUsers() {
final String sql = "SELECT id,name FROM userProfile";
try {
return jdbcTemplate.query(sql, (resultSet) -> {
UUID id = UUID.fromString(resultSet.getString("id"));
String name = resultSet.getString("name");
return new User(id, name);
});
} catch (SQLException e) {
e.printStackTrace();
return null;
}
}
}
PostgresDataSource.java
package com.example.demo.datasource;
import com.zaxxer.hikari.HikariDataSource;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
#Configuration
public class PostgresDataSource {
#Bean
#ConfigurationProperties("app.datasource")
public HikariDataSource hikariDataSource() {
return DataSourceBuilder
.create()
.type(HikariDataSource.class)
.build();
}
}
Hi I had directly the same problem.
Problem was That when you automatically import library, there are two options.
Flyway or Springframework.
If you import flyway, than you have this problem.
import org.flywaydb.core.internal.jdbc.JdbcTemplate;
If you import spriongwramework everything is OK
import org.springframework.jdbc.core.JdbcTemplate;
I found two problem.
as #stefic said, you should modify your import jdbcTemplate
you should modify your jdbcTemplate query
UserDataAccessService.java
#Override
public List<User> selectAllUsers() {
final String sql = "SELECT id,name FROM userProfile";
return jdbcTemplate.query(sql, (resultSet, i) -> { // <----- add second parameter `i`
UUID id = UUID.fromString(resultSet.getString("id"));
String name = resultSet.getString("name");
return new User(id, name);
});
}

Spring-Boot + Camel + producerTemplate = thousands of threads

---UPDATE---
As it turns out the heap is getting emptied after some time. However the number of threads just grows without end. On my mac with 8Gb of RAM I am fine, but on a production machine with 1Gb I am getting:
Exception in thread "Thread-341" java.lang.OutOfMemoryError: unable to create new native thread
I did write a simple app using Spring Boot (1.2.7.RELEASE) and Apache Camel (2.15.0). The app is simple and has only 1 route: a timer will invoke a method on a bean every 1s. The method invoked will use ProducerTemplate to ssh into a remote machine, execute a small script, and print out the output to the console. Simple, right?
However, when profiling this, I can see the number of threads, and heap go through the roof! It seems like any threads created for the ssh are never killed, but parked instead. Because of that I run OOM pretty quickly.
Let me show you some profiler output:
As you can see the threads/heap go up and up very quickly.
The app code is minimal, so I will provide it all here for reference.
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>tests</groupId>
<artifactId>camel-producer-template-testing</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<start-class>app.Application</start-class>
<camel.version>2.15.0</camel.version>
<spring-boot.version>1.2.7.RELEASE</spring-boot.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-core</artifactId>
<version>${camel.version}</version>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-spring</artifactId>
<version>${camel.version}</version>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-spring-boot</artifactId>
<version>${camel.version}</version>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-ftp</artifactId>
<version>${camel.version}</version>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-ssh</artifactId>
<version>${camel.version}</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<!-- Import dependency management from Spring Boot -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<finalName>${project.artifactId}-${project.version}</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.2</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring-boot.version}</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Application.java:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import java.util.TimeZone;
#Configuration
#EnableAutoConfiguration
#ComponentScan
public class Application {
public static void main(String[] args) {
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
SpringApplication application = new SpringApplication(Application.class);
application.run(args);
}
}
MyAppContext.java:
import org.apache.camel.CamelContext;
import org.apache.camel.RoutesBuilder;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.spring.SpringCamelContext;
import org.apache.sshd.common.keyprovider.FileKeyPairProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
#Configuration
#PropertySource("application.properties")
public class MyAppContext {
private final String sshKeyPath = "/Users/gruszd/.ssh/id_rsa";
#Autowired
private ApplicationContext applicationContext;
#Bean
public CamelContext camelContext() {
return new SpringCamelContext(applicationContext);
}
#Bean
FileKeyPairProvider keyPairProvider() {
return new FileKeyPairProvider(new String[]{sshKeyPath});
}
#Bean
RoutesBuilder myRouter() {
return new RouteBuilder() {
#Override
public void configure() throws Exception {
from("timer://foo?period=1000").to("bean:sftpStager?method=stage");
}
};
}
}
SftpStager.java:
import org.apache.camel.ProducerTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
#Component
public class SftpStager {
#Autowired
private ProducerTemplate producerTemplate;
public void stage() throws Exception {
String response = producerTemplate.requestBody(
"ssh://_remote.machine.url.here_?username=_username_&keyPairProvider=#keyPairProvider",
"/home/_username_/some_temp_script.sh",
String.class);
System.out.println("----");
System.out.println(response);
System.out.println("----");
}
}
As you can see the app is very minimal, and it works (I can see the output of the remote script in my console where the app is running). But like I said, it eats up memory like fresh cookies!
Now I did read this . However, in my app the ProducerTemplate is a bean instantiated by the Camelcontext itself. Therefore I can't producerTemplate.stop() because the next trigger would throw an exception saying the template is not started...
So my main question is: am I using the ProducerTemplate in a wrong way? And if I do, how should I use it?
If I am not doing anything wrong, is that a bug? Should I report it?
As noted by the original poster:
Turns out it is a bug in Apache Camel itself, should be [and was] fixed in 2.16.2: Jira Issue here
You must stop / clear the state of the producerTemplate.
There are in-built methods like producerTemplate.stop() or in your case, since you had autowired the Producer template, you could try producerTemplate.cleanUp()

Bean type not found when using Spring aspect and java config

I added an aspect to a working Spring+Wicket application to log thrown exceptions, and now I get the following error whenever I load the Report page:
ERROR | 2013-12-09 08:42:06,149 | qtp1559334851-16 | DefaultExceptionMapper:123 - Unexpected error occurred
org.apache.wicket.WicketRuntimeException: Can't instantiate page using constructor 'public org.jonblack.ReportPage() throws java.lang.Exception'. An exception has been thrown during construction!
at org.apache.wicket.session.DefaultPageFactory.newPage(DefaultPageFactory.java:194)
at org.apache.wicket.session.DefaultPageFactory.newPage(DefaultPageFactory.java:67)
...
Caused by: java.lang.IllegalStateException: bean of type [org.jonblack.ReportController] not found
at org.apache.wicket.spring.injection.annot.AnnotProxyFieldValueFactory.getBeanNameOfClass(AnnotProxyFieldValueFactory.java:236)
at org.apache.wicket.spring.injection.annot.AnnotProxyFieldValueFactory.getBeanName(AnnotProxyFieldValueFactory.java:179)
...
I'm using java configuration for the project, so there is no applicationContext.xml. All configuration is done via annotations, the bulk of which are in AppConfig.java.
All the code for my application is shown below. I've left out the HTML templates and HomePage as they aren't integral to the problem.
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>org.jonblack</groupId>
<artifactId>sw-p2</artifactId>
<packaging>war</packaging>
<version>1.0-SNAPSHOT</version>
<!-- TODO project name -->
<name>sw-p2</name>
<description></description>
<licenses>
<license>
<name>The Apache Software License, Version 2.0</name>
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
<distribution>repo</distribution>
</license>
</licenses>
<properties>
<aspectj.version>1.7.4</aspectj.version>
<spring.version>3.2.4.RELEASE</spring.version>
<wicket.version>6.11.0</wicket.version>
<jetty.version>7.6.3.v20120416</jetty.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- WICKET DEPENDENCIES -->
<dependency>
<groupId>org.apache.wicket</groupId>
<artifactId>wicket-core</artifactId>
<version>${wicket.version}</version>
</dependency>
<dependency>
<groupId>org.apache.wicket</groupId>
<artifactId>wicket-extensions</artifactId>
<version>${wicket.version}</version>
</dependency>
<dependency>
<groupId>org.wicketstuff</groupId>
<artifactId>wicketstuff-annotation</artifactId>
<version>${wicket.version}</version>
</dependency>
<dependency>
<groupId>org.apache.wicket</groupId>
<artifactId>wicket-spring</artifactId>
<version>${wicket.version}</version>
</dependency>
<!-- Spring dependencies -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- aspectj -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${aspectj.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>${aspectj.version}</version>
</dependency>
<!-- LOGGING DEPENDENCIES - LOG4J -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.6.4</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.16</version>
</dependency>
<!-- JUNIT DEPENDENCY FOR TESTING -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
<scope>test</scope>
</dependency>
<!-- JETTY DEPENDENCIES FOR TESTING -->
<dependency>
<groupId>org.eclipse.jetty.aggregate</groupId>
<artifactId>jetty-all-server</artifactId>
<version>${jetty.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<filtering>false</filtering>
<directory>src/main/resources</directory>
</resource>
<resource>
<filtering>false</filtering>
<directory>src/main/java</directory>
<includes>
<include>**</include>
</includes>
<excludes>
<exclude>**/*.java</exclude>
</excludes>
</resource>
</resources>
<testResources>
<testResource>
<filtering>false</filtering>
<directory>src/test/resources</directory>
</testResource>
<testResource>
<filtering>false</filtering>
<directory>src/test/java</directory>
<includes>
<include>**</include>
</includes>
<excludes>
<exclude>**/*.java</exclude>
</excludes>
</testResource>
</testResources>
<plugins>
<plugin>
<inherited>true</inherited>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.5.1</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
<encoding>UTF-8</encoding>
<showWarnings>true</showWarnings>
<showDeprecation>true</showDeprecation>
</configuration>
</plugin>
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>${jetty.version}</version>
<configuration>
<connectors>
<connector implementation="org.eclipse.jetty.server.nio.SelectChannelConnector">
<port>8080</port>
<maxIdleTime>3600000</maxIdleTime>
</connector>
<connector implementation="org.eclipse.jetty.server.ssl.SslSocketConnector">
<port>8443</port>
<maxIdleTime>3600000</maxIdleTime>
<keystore>${project.build.directory}/test-classes/keystore</keystore>
<password>wicket</password>
<keyPassword>wicket</keyPassword>
</connector>
</connectors>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-eclipse-plugin</artifactId>
<version>2.9</version>
<configuration>
<downloadSources>true</downloadSources>
</configuration>
</plugin>
</plugins>
</build>
</project>
AppConfig.java
package org.jonblack;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.Executor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ComponentScan;
//import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
#Configuration
#ComponentScan("org.jonblack")
#EnableAsync
#EnableAspectJAutoProxy()
public class AppConfig {
private static final Logger log = LoggerFactory.getLogger(AppConfig.class);
#Bean
public ReportController reportController() {
log.info("Getting ReportController");
return new ReportController();
}
#Bean
public ThreadPoolTaskExecutor taskExecutor() {
ThreadPoolTaskExecutor pool = new ThreadPoolTaskExecutor();
pool.setCorePoolSize(5);
pool.setMaxPoolSize(10);
pool.setWaitForTasksToCompleteOnShutdown(true);
return pool;
}
#Bean
public ExceptionLoggingAspect exceptionLoggingAspect() {
return new ExceptionLoggingAspect();
}
#Bean
public AnnotationAwareAspectJAutoProxyCreator annotationAwareAspectJAutoProxyCreator() {
AnnotationAwareAspectJAutoProxyCreator aop = new AnnotationAwareAspectJAutoProxyCreator();
return aop;
}
}
ExceptionLoggingAspect.java
package org.jonblack;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
#Aspect
#Component
public class ExceptionLoggingAspect {
private static final Logger LOG = LoggerFactory.getLogger(ExceptionLoggingAspect.class);
#AfterThrowing(pointcut="execution(* org.jonblack.ReportController.getReportData(..))", throwing="ex")
public void afterThrowing(Throwable ex) {
LOG.error(ex.getMessage());
}
}
ReportController.java
package org.jonblack;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
//import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Controller;
#Controller
public class ReportController {
private static final Logger log = LoggerFactory.getLogger(ReportController.class);
#Autowired
private ThreadPoolTaskExecutor taskExecutor;
#Async
public Future<String> getReportData() throws Exception {
log.info("Entered into getReportData()");
try {
log.info("Throwing an exception");
throw new Exception("Something went wrong");
} catch(Exception ex) {
log.error("In catch block: {}", ex.getMessage());
}
final Future<String> result = taskExecutor.submit(new Callable<String>() {
#Override
public String call() throws Exception {
return "not a fancy result";
}
});
log.info("Returning from getReportData()");
return result;
}
}
ReportPage.java
package org.jonblack;
import java.util.concurrent.Future;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.wicket.markup.html.WebPage;
import org.apache.wicket.spring.injection.annot.SpringBean;
import org.wicketstuff.annotation.mount.MountPath;
#MountPath("report")
public class ReportPage extends WebPage {
private static final Logger log = LoggerFactory.getLogger(ReportPage.class);
#SpringBean
ReportController reportController;
public ReportPage() throws Exception {
log.info("Starting ReportPage");
reportController.getReportData();
}
}
WicketApplication.java
package org.jonblack;
import org.apache.wicket.markup.html.WebPage;
import org.apache.wicket.protocol.http.WebApplication;
import org.apache.wicket.spring.injection.annot.SpringComponentInjector;
import org.wicketstuff.annotation.scan.AnnotatedMountScanner;
public class WicketApplication extends WebApplication
{
#Override
public Class<? extends WebPage> getHomePage()
{
return HomePage.class;
}
#Override
public void init()
{
super.init();
// Spring
getComponentInstantiationListeners().add(
new SpringComponentInjector(this));
// Annotation-driven page mounting
new AnnotatedMountScanner().scanPackage("org.jonblack").mount(this);
}
}
web.xml
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
<display-name>sw-p2</display-name>
<!-- Configuration loading -->
<context-param>
<param-name>contextClass</param-name>
<param-value>
org.springframework.web.context.support.AnnotationConfigWebApplicationContext
</param-value>
</context-param>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>org.jonblack.AppConfig</param-value>
</context-param>
<!-- Spring -->
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<!-- Wicket -->
<filter>
<filter-name>wicket.sw-p2</filter-name>
<filter-class>org.apache.wicket.protocol.http.WicketFilter</filter-class>
<init-param>
<param-name>applicationClassName</param-name>
<param-value>org.jonblack.WicketApplication</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>wicket.sw-p2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
I've followed the Spring reference for Aspects but it's very thin on the ground when it comes to java configurations (and I do find the reference to be quite hard to follow).
I've also done the obligatory DuckDuckGo search and found only references to XML configurations.
On stackoverflow itself I have found this post which explains the same problem, but the cause in that instance was an incorrect annotation and incorrectly named applicationContext.xml file: neither of these helped resolve my situation. I tried using #Autowired instead of #SpringBean, and got the same NullPointerException. Given that the linked post resolved it without this change, I assume this isn't the right path to take.
The problem lies in your configuration.
#Bean
public AnnotationAwareAspectJAutoProxyCreator annotationAwareAspectJAutoProxyCreator() {
AnnotationAwareAspectJAutoProxyCreator aop = new AnnotationAwareAspectJAutoProxyCreator();
return aop;
}
This bean leads to creation of a proxy of a proxy. The #EnableAspectJAutoProxy annotation already registers an AutoProxyCreator and due to the existence of multiple, different instances, this will lead to proxy duplication.
Next to that the additional declaration of your aspect might lead to 2 aspects being instantiated.
#Bean
public ExceptionLoggingAspect exceptionLoggingAspect() {
return new ExceptionLoggingAspect();
}
Your #Aspect is also an #Component and as such will be detected by the #ComponentScan functionality.
Basically removing both beans should fix your problem.
public Future<String> getReportData() throws Exception {
log.info("Entered into getReportData()");
try {
log.info("Throwing an exception");
throw new Exception("Something went wrong");
} catch(Exception ex) { // This catch blocks swallows the exception
log.error("In catch block: {}", ex.getMessage());
}
}
Next to your configuration problems, you also have a problem with your code. Basically your aspect is useless. You have a try/catch block in your code which swallows the Exception. This swallowing leads to a situation where your aspect never sees the exception and will never trigger. From your aspects point of view the exception never happened.
Either don't catch and simply let the Exception bubble up the stack or rethrow the Exception.

Resources