I am pretty new to spring-boot, apache camel and ActiveMQ broker. I am trying to create an application which will send a message to a queue which I am hosting locally using Camel for routing.
When I run the app, I get the error :
ERROR org.apache.camel.FailedToCreateRouteException: Failed to create route route1 at: >>> To[activemq:queue:myQueue] <<< in route: Route(route1)[[From[direct:firstRoute]] -> [SetBody[constant... because of Failed to resolve endpoint: activemq://queue:myQueue due to: No component found with scheme: activemq
POM:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-activemq</artifactId>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-spring-boot-starter</artifactId>
<version>2.22.0</version>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-core</artifactId>
<version>2.22.0</version>
</dependency>
MsgRouteBuilder:
public void configure() throws Exception {
from("direct:firstRoute")
.setBody(constant("Hello"))
.to("activemq:queue:myQueue");
}
application.yaml:
activemq:
broker-url: tcp://localhost:61616
user: meAd
password: meAd
MainApp.java:
package me.ad.myCamel;
import org.apache.camel.CamelContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import me.ad.myCamel.router.MessageRouteBuilder;
#SpringBootApplication
#EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class})
#EnableAspectJAutoProxy(proxyTargetClass = true)
#EnableCaching
public class MeAdApp implements CommandLineRunner {
private static final Logger LOG = LoggerFactory.getLogger(MeAdApp.class);
#Autowired
private CamelContext camelContext;
public static void main(String[] args) {
try {
SpringApplication.run(MeAdApp.class, args);
} catch (Exception ex) {
LOG.error(ex.getMessage(), ex);
}
}
#Override
public void run(String... args) throws Exception {
LOG.info("Starting MeAdApp...");
}
#Bean
public MsgRouteBuilder msgRouteBuilder() throws Exception {
MsgRouteBuilder routeBuilder = new MsgRouteBuilder();
camelContext.addRoutes(routeBuilder);
return routeBuilder;
}
}
Can anybody please point me to the right direction as to why I am getting this error ? Any help is greatly appreciated .
You need to add camel-activemq in the POM.xml file
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-activemq</artifactId>
<version>3.2.0</version>
</dependency>
Your application doesn't know the component activemq. To resolve that, you need to add the dependency of camel-activemq in your pom.xml file :
<properties>
...
<activemq.version>3.1.0</activemq.version>
</properties>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-activemq</artifactId>
<version>${activemq.version}</version>
</dependency>
Related
I'm creating an application with spring boot and I want to authenticate my application using JWT but it is in microservice. In the JWT service it runs normally but I want to authenticate all the microservice services so I put the JWT service code for the api-gateway but because it uses spring-cloud-starter-gateway I can't use spring-boot-starter-web so far everything well. My big problem is that when I run some service, a login page appears. I wanted to remove this page does anyone have any idea how to do this?
Here is my application code below:
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.7.4</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>routing</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>routing</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>17</java.version>
<spring-cloud.version>2021.0.4</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<version>3.1.4</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
<version>3.1.4</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
application.properties:
server.port=8080
spring.application.name=routing
eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka/
eureka.instance.hostname=localhost
spring.cloud.gateway.discovery.locator.enabled=true
rsa.publickey=classpath:carts/public.pem
rsa.privatekey=classpath:carts/private.pem
#spring.main.web-application-type=reactive
spring.cloud.gateway.enabled=true
spring.cloud.gateway.routes[0].id=user
spring.cloud.gateway.routes[0].uri=lb://USER
spring.cloud.gateway.routes[0].predicates=Path=/user/**
spring.cloud.gateway.routes[1].id=testes
spring.cloud.gateway.routes[1].uri=lb://TESTES
spring.cloud.gateway.routes[1].predicates=Path=/testes/**
spring.cloud.gateway.routes[2].id=user-create
spring.cloud.gateway.routes[2].uri=lb://USER-CREATE
spring.cloud.gateway.routes[2].predicates=Path=/user-create/**
spring.cloud.gateway.routes[3].id=jwt
spring.cloud.gateway.routes[3].uri=lb://JWT
spring.cloud.gateway.routes[3].predicates=Path=/**
RsaKeyPropreties.java:
package com.example.routing.config;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import org.springframework.boot.context.properties.ConfigurationProperties;
#ConfigurationProperties(prefix = "rsa")
public record RsaKeyPropreties(RSAPublicKey publickey,RSAPrivateKey privatekey) {
}
SecurityConfig.java:
package com.example.routing.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.oauth2.server.resource.OAuth2ResourceServerConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.oauth2.jwt.JwtDecoder;
import org.springframework.security.oauth2.jwt.JwtEncoder;
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
import org.springframework.security.oauth2.jwt.NimbusJwtEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
import com.nimbusds.jose.proc.SecurityContext;
import com.nimbusds.jose.jwk.JWK;
import com.nimbusds.jose.jwk.JWKSet;
import com.nimbusds.jose.jwk.RSAKey;
import com.nimbusds.jose.jwk.source.ImmutableJWKSet;
import com.nimbusds.jose.jwk.source.JWKSource;
import static org.springframework.security.config.Customizer.withDefaults;
import org.springframework.boot.autoconfigure.AutoConfiguration;
#Configuration
#AutoConfiguration
#EnableWebSecurity
public class SecurityConfig {
private final RsaKeyPropreties Rsakeys;
public SecurityConfig(RsaKeyPropreties Rsakeys) {
this.Rsakeys = Rsakeys;
}
#Bean
public InMemoryUserDetailsManager user(){
return new InMemoryUserDetailsManager(
User.withUsername("username")
.password("{noop}password")
.authorities("read")
.build()
);
}
#Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception{
return http
.csrf(csrf->csrf.disable())
//.authorizeRequests(auth->auth.antMatchers("/user**").authenticated())
.authorizeRequests(auth->auth.anyRequest().authenticated())
.oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt)
.sessionManagement(session->session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.httpBasic(withDefaults()).build();
}
#Bean
JwtDecoder jwtDecoder() {
return NimbusJwtDecoder.withPublicKey(Rsakeys.publickey()).build();
}
#Bean
JwtEncoder jwtEncoder() {
JWK jwk = new RSAKey.Builder(Rsakeys.publickey()).privateKey(Rsakeys.privatekey()).build();
JWKSource<SecurityContext> jws = new ImmutableJWKSet<>(new JWKSet(jwk));
return new NimbusJwtEncoder(jws);
}
}
RoutingApplication.java:
package com.example.routing;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import com.example.routing.config.RsaKeyPropreties;
#EnableConfigurationProperties(RsaKeyPropreties.class)
#SpringBootApplication
#EnableDiscoveryClient
public class RoutingApplication {
public static void main(String[] args) {
SpringApplication.run(RoutingApplication.class, args);
}
}
Thanks!
For Servlet app, this will return 401 (unauthorized) instead of 302 (redirect to login) when authorization is missing or invalid:
http.exceptionHandling().authenticationEntryPoint((request, response, authException) -> {
response.addHeader(HttpHeaders.WWW_AUTHENTICATE, "Basic realm=\"Restricted Content\"");
response.sendError(HttpStatus.UNAUTHORIZED.value(), HttpStatus.UNAUTHORIZED.getReasonPhrase());
});
For a reactive app, you can provide a ServerAccessDeniedHandler bean instead:
#Bean
ServerAccessDeniedHandler serverAccessDeniedHandler() {
return (var exchange, var ex) -> exchange.getPrincipal().flatMap(principal -> {
final var response = exchange.getResponse();
response.setStatusCode(principal instanceof AnonymousAuthenticationToken ? HttpStatus.UNAUTHORIZED : HttpStatus.FORBIDDEN);
response.getHeaders().setContentType(MediaType.TEXT_PLAIN);
final var dataBufferFactory = response.bufferFactory();
final var buffer = dataBufferFactory.wrap(ex.getMessage().getBytes(Charset.defaultCharset()));
return response.writeWith(Mono.just(buffer)).doOnError(error -> DataBufferUtils.release(buffer));
});
}
Spring-boot starters I maintain here (which are thin wrappers arround spring-boot-starter-oauth2-resource-server) are doing that by default plus a few other usefull things:
map authorities from a list of claims of your choice (giving you hand on case and prefix)
stateless session-management (like you do)
disabled CSRF (only if session-management is left stateless)
fine grained CORS config from properties
multi-tenancy (accept more than just one JWT issuer)
As a side note, what about having your gateway being a pass-through for OAuth2 (just forward requests authorization header and responses HTTP status) and implement resources access-control (spring-security .authorizeRequests() and #PreAuthorize rules) on resource-server, where you can unit-test it?
I'm running into an issue where I can't run JUnit5 tests using Maven. Running them in the IDE works just fine but using "mvn test" produces the following output:
T E S T S
[INFO] -------------------------------------------------------
[INFO]
[INFO] Results:
[INFO]
[INFO] Tests run: 0, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
Here are my test classes :
package com.example.spstream.controllers.events;
import com.example.spstream.entities.Event;
import com.example.spstream.repositories.EventRepository;
import com.example.spstream.repositories.UserRepository;
import com.example.spstream.util.Mapper;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.boot.test.mock.mockito.SpyBean;
import org.springframework.dao.DataAccessException;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import java.time.LocalDateTime;
import static org.hamcrest.Matchers.containsString;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
#AutoConfigureMockMvc
#EnableAutoConfiguration(exclude = SecurityAutoConfiguration.class)
public class EventsCreationTest {
private static final String MISSING_TITLE_ERROR_MESSAGE = "title is missing";
private static final String MISSING_ACTIVITY_ERROR_MESSAGE = "activity is missing";
private static final String MISSING_LOCALISATION_ERROR_MESSAGE = "localisation is missing";
private static final String INVALID_ORGANISER_ID_ERROR_MESSAGE = "user %s does not exist";
private static final String MISSING_ORGANISER_ID_ERROR_MESSAGE = "organiser id is missing";
#Autowired
private MockMvc mockMvc;
#MockBean
private UserRepository userRepository;
#SpyBean
private EventRepository eventRepository;
private static final String DATE_IN_PAST_ERROR_MESSAGE = "date is in the past";
#BeforeEach
public void reset(){
Mockito.reset(userRepository);
Mockito.when(userRepository.existsById("123456")).thenReturn(true);
}
//prevents hardcoded events from failing tests due to date in the past
public void setEventDateToTomorrow(Event event) {
event.setDateTime(LocalDateTime.now().plusDays(1));
}
public void setEventDateToYesterday(Event event) {
event.setDateTime(LocalDateTime.now().minusDays(1));
}
public void testCorrectEventCreationWithEvent(Event event) throws Exception {
mockMvc.perform(MockMvcRequestBuilders.post("/events")
.content(Mapper.writeObjectToJson(event))
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isCreated())
.andExpect(jsonPath("$.id").exists())
.andExpect(jsonPath("$.id").isString());
}
public void testIncorrectEventCreationWithEvent(Event event, String errorMessagePattern) throws Exception {
mockMvc.perform(MockMvcRequestBuilders.post("/events")
.content(Mapper.writeObjectToJson(event))
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isBadRequest())
.andExpect(content().string(containsString(String.format(errorMessagePattern, event.getOrganiserId()))));
}
/**
* correct data
**/
#Test
public void testMinimalCorrectEvent() throws Exception {
Event minimalEvent = Mapper.readObjectFromJson(Mapper.readJsonFromFile("controllers/events/create/correct/minimal_event.json"), Event.class);
setEventDateToTomorrow(minimalEvent);
testCorrectEventCreationWithEvent(minimalEvent);
}
#Test
public void testMaximalCorrectEvent() throws Exception {
Event maximalEvent = Mapper.readObjectFromJson(Mapper.readJsonFromFile("controllers/events/create/correct/maximal_event.json"), Event.class);
setEventDateToTomorrow(maximalEvent);
testCorrectEventCreationWithEvent(maximalEvent);
}
/**
* missing data
**/
#Test
public void testIncorrectEventTitleMissing() throws Exception {
Event eventTitleMissing = Mapper.readObjectFromJson(Mapper.readJsonFromFile("controllers/events/create/correct/minimal_event.json"), Event.class);
setEventDateToTomorrow(eventTitleMissing);
eventTitleMissing.setTitle(null);
testIncorrectEventCreationWithEvent(eventTitleMissing, MISSING_TITLE_ERROR_MESSAGE);
}
#Test
public void testIncorrectEventActivityMissing() throws Exception {
Event eventActivityMissing = Mapper.readObjectFromJson(Mapper.readJsonFromFile("controllers/events/create/correct/minimal_event.json"), Event.class);
eventActivityMissing.setActivity(null);
setEventDateToTomorrow(eventActivityMissing);
testIncorrectEventCreationWithEvent(eventActivityMissing, MISSING_ACTIVITY_ERROR_MESSAGE);
}
#Test
public void testIncorrectEventLocalisationMissing() throws Exception {
Event eventLocalisationMissing = Mapper.readObjectFromJson(Mapper.readJsonFromFile("controllers/events/create/correct/minimal_event.json"), Event.class);
eventLocalisationMissing.setLocalisation(null);
setEventDateToTomorrow(eventLocalisationMissing);
testIncorrectEventCreationWithEvent(eventLocalisationMissing, MISSING_LOCALISATION_ERROR_MESSAGE);
}
#Test
public void testIncorrectEventMissingUserId() throws Exception {
Event eventOrganiserIdMissing = Mapper.readObjectFromJson(Mapper.readJsonFromFile("controllers/events/create/incorrect/missing_user_id.json"), Event.class);
setEventDateToTomorrow(eventOrganiserIdMissing);
testIncorrectEventCreationWithEvent(eventOrganiserIdMissing, MISSING_ORGANISER_ID_ERROR_MESSAGE);
}
/**
* invalid data
**/
#Test
public void testIncorrectEventInvalidOrganiserId() throws Exception {
Mockito.when(userRepository.existsById(Mockito.any())).thenReturn(false);
Event eventInvalidOrganiserId = Mapper.readObjectFromJson(Mapper.readJsonFromFile("controllers/events/create/correct/minimal_event.json"), Event.class);
setEventDateToTomorrow(eventInvalidOrganiserId);
testIncorrectEventCreationWithEvent(eventInvalidOrganiserId, INVALID_ORGANISER_ID_ERROR_MESSAGE);
}
#Test
public void testIncorrectEventDateInThePast() throws Exception {
Event eventInPast = Mapper.readObjectFromJson(Mapper.readJsonFromFile("controllers/events/create/correct/minimal_event.json"), Event.class);
setEventDateToYesterday(eventInPast);
testIncorrectEventCreationWithEvent(eventInPast, DATE_IN_PAST_ERROR_MESSAGE);
}
/**
* internal database issue
**/
#Test
public void testCorrectEventServerError() throws Exception {
Event eventInvalidOrganiserId = Mapper.readObjectFromJson(Mapper.readJsonFromFile("controllers/events/create/correct/minimal_event.json"), Event.class);
setEventDateToTomorrow(eventInvalidOrganiserId);
Mockito.when(eventRepository.save(eventInvalidOrganiserId)).thenThrow(Mockito.mock(DataAccessException.class));
mockMvc.perform(MockMvcRequestBuilders.post("/events")
.content(Mapper.writeObjectToJson(eventInvalidOrganiserId))
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().is5xxServerError());
System.out.println("whatever");
}
}
package com.example.spstream.controllers.events;
import com.example.spstream.entities.Event;
import com.example.spstream.repositories.EventRepository;
import com.example.spstream.util.Mapper;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.dao.DataAccessException;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import java.util.List;
import java.util.Optional;
import static com.example.spstream.util.Mapper.readJsonFromFile;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
#AutoConfigureMockMvc
#EnableAutoConfiguration(exclude = SecurityAutoConfiguration.class)
public class EventsAccessTest {
#MockBean
EventRepository mockEventRepository;
#Autowired
MockMvc mockMvc;
#BeforeEach
public void reset(){
Mockito.reset(mockEventRepository);
}
#Test
public void testFindAll() throws Exception{
List<Event> events = Mapper.readObjectListFromJson(readJsonFromFile("controllers/events/access/all_events.json"), Event.class);
Mockito.when(mockEventRepository.findAll()).thenReturn(events);
mockMvc.perform(MockMvcRequestBuilders.get("/events")
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(content().json(Mapper.readJsonFromFile("controllers/events/access/all_events.json")));
}
#Test
public void testFindEventWhichExists() throws Exception{
Mockito.when(mockEventRepository.findById("123456")).thenReturn(Optional.of(Mapper.readObjectFromJson(Mapper.readJsonFromFile("controllers/events/access/final_event.json"),Event.class)));
mockMvc.perform(MockMvcRequestBuilders.get("/events/123456")
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(content().json(Mapper.readJsonFromFile("controllers/events/access/final_event.json")));
}
#Test
public void testFindEventWhichDoesntExist() throws Exception {
Mockito.when(mockEventRepository.findById("7891011")).thenReturn(Optional.empty());
mockMvc.perform(MockMvcRequestBuilders.get("/events/7891011")
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isNotFound())
.andExpect(content().contentType(MediaType.APPLICATION_JSON));
}
#Test
public void testFindEventDatabaseError() throws Exception {
Mockito.when(mockEventRepository.findById("123456")).thenThrow(Mockito.mock(DataAccessException.class));
mockMvc.perform(MockMvcRequestBuilders.get("/events/123456")
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().is5xxServerError());
}
}
The pom :
<?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.6.2</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>spstream</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spstream</name>
<description>spstream</description>
<properties>
<java.version>17</java.version>
<testcontainers.version>1.16.2</testcontainers.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jdbc</artifactId>
</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.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>postgresql</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.github.tomakehurst</groupId>
<artifactId>wiremock-jre8</artifactId>
<version>2.32.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.8.2</version>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers-bom</artifactId>
<version>${testcontainers.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M5</version>
<dependencies>
<dependency>
<groupId>org.apache.maven.surefire</groupId>
<artifactId>surefire-junit47</artifactId>
<version>3.0.0-M5</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
</project>
I have done some research and I figured it might have something to do mith mixing up JUnit4 and JUnit5 features which leads to maven surefire plugin not running tests. However I can't find where those leftover JUnit4 features might be.
I'd appreciate any help.
As pointed out by other comments and answers I had residual JUnit4 dependencies due to test containers. I was able to fix the issue by explicitly setting JUnit5 as a dependency for maven surefire plugin like so :
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M5</version>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.8.2</version>
</dependency>
</dependencies>
</plugin>
The Junit4 is available because of Testcontainer dependency.
Testcontainers have a dependency on Junit4 and have it available by default.
You might also encounter the following issue in few cases:
IDE's detects the test cases written in Junit4 format but in sometime in case you make the test classes and methods package-private, they don't detect it.
I am not sure if they would be removing it in further releases but they do have Junit5 support which should resolve the issue
https://www.testcontainers.org/test_framework_integration/junit_5/
It's my first post so feel free to leave some feedback or if i do something wrong :)
I am using spring-boot and resteasy :
<!-- Spring Boot -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.1.0.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.paypal.springboot</groupId>
<artifactId>resteasy-spring-boot-starter</artifactId>
<version>2.3.4-RELEASE</version>
</dependency>
I am trying to use Swagger to have a view of my endpoints, so I added this dependency :
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
This dependencies are loaded to my repo, everything looks good.
I added this class to make the easiest config class :
#Configuration
#EnableSwagger2
public class SwaggerConfig {
#Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.any())
.paths(PathSelectors.any())
.build();
}
}
When i Launch the app in the debug mod I enter in this previous Bean. Evrything looks fine.
When I launch the Spring app :
#SpringBootApplication
#EnableAutoConfiguration(exclude={MongoAutoConfiguration.class,RabbitAutoConfiguration.class})
public class SituationServicesApplication implements CommandLineRunner {
public static void main(String[] args) {
SpringApplication.run(SituationServicesApplication.class, args);
}
#Override
public void run(String... args) throws Exception {
}
}
Everything looks fine :
2019-07-06 15:43:27.222 INFO 6336 --- [ main] pertySourcedRequestMappingHandlerMapping : Mapped URL path [v2/api-docs] onto method [public org.springframework.http.ResponseEntity<springfox.documentation.spring.web.json.Json> springfox.documentation.swagger2.web.Swagger2Controller.getDocumentation(java.lang.String,javax.servlet.http.HttpServletRequest)]
But when I try to reach the swagger-ui.html :
http://localhost:8092/test/v2/api-docs
or
http://localhost:8092/test/swagger-ui.html
I've got a 404 error :
"RESTEASY003210: Could not find resource for full path:
http://localhost:8092/test/v2/api-docs".
I tried to modify the default URL by adding a property : springfox.documentation.swagger.v2.path=v2/api-docs-test
It stills 404.
I tried from scratch with a new empty project and it worked just fine. Something is wrong with my project I guess.
I am sure of the URL used.
Do you know how I can debug this issue? Can I see some created source from Swagger?
If I can put some log on it to know where the issue comes from?
If you are using Spring Security, then you have to add some more configuration as below.
Complete Working Example
SecurityConfig.java
package com.swagger.demo.security;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter implements WebMvcConfigurer{
//Swagger Resources
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
}
//If you are using Spring Security Add Below Configuration
#Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers("/v2/api-docs", "/configuration/**", "/swagger*/**", "/webjars/**")
.antMatchers(HttpMethod.OPTIONS,"/**");
}
#Override
protected void configure(HttpSecurity http) throws Exception{
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/**", "/v2/api-docs", "/configuration/**", "/swagger*/**", "/webjars/**")
.permitAll()
.anyRequest().authenticated();
}
}
SwaggerConfig.java
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
#Configuration
#EnableSwagger2
public class SwaggerConfig {
#Bean
public Docket apiDocket() {
Docket docket = new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.basePackage("com.swagger.demo"))
.paths(PathSelectors.any())
.build();
return docket;
}
}
pom.xml
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-core</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
#Pierrot, could you please check whether the context-path and port configured in application and the one used in the URL to test swagger UI is correct?
As you mentioned that when you created a new project from scratch it worked fine, the issue may be with the context-path/port.
I made two classes:
Main class with embedded Tomcat(8.5.20)
ServerEndpoint of Websocket
I run the main class on IntelliJ IDEA
and run this JavaScript: new WebSocket('ws://localhost:8080/ws')
in the console of Google Chrome.
I expected the response code is 200, but actually it is 404.
How can I fix this?
Main class:
package webapp;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.startup.Tomcat;
import javax.servlet.ServletException;
import java.io.File;
public class Main {
private static final String STATIC_DIR = "src/main/static/";
public static void main(String[] args) throws ServletException, LifecycleException {
Tomcat tomcat = new Tomcat();
tomcat.setPort(8080);
File staticDir = new File(STATIC_DIR);
tomcat.addWebapp("/", staticDir.getAbsolutePath());
tomcat.start();
tomcat.getServer().await();
}
}
ServerEndpoint:
package webapp.websocket;
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
#ServerEndpoint("/ws")
public class SampleWebSocket {
#OnOpen
public void onOpen(Session session) {
System.out.println("open");
}
#OnClose
public void onClose(Session session) {
System.out.println("close");
}
#OnMessage
public String onMessage(String text) {
System.out.println("message:" + text);
return "Server:" + text;
}
}
Thank you.
I found a solution.
This question is dupricated.
I read Got 404 error on tomcat 7.0.47 websocket and editted my pom.xml.
Following is the whole of 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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>websocket-sample</artifactId>
<version>1.0.0-SNAPSHOT</version>
<name>websocket-sample</name>
<properties>
<java.version>1.8</java.version>
<maven.compiler.target>${java.version}</maven.compiler.target>
<maven.compiler.source>${java.version}</maven.compiler.source>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-core</artifactId>
<version>8.5.20</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-websocket</artifactId>
<version>8.5.20</version>
</dependency>
<dependency>
<groupId>javax.websocket</groupId>
<artifactId>javax.websocket-api</artifactId>
<version>1.1</version>
</dependency>
</dependencies>
</project>
Just add the following dependency to pom.xml
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-websocket</artifactId>
<version>8.5.20</version>
</dependency>
What solved the issue for me was switching from the javax.websocket-api dependency to the Tomcat-specific tomcat-embed-websocket dependency instead and switching all my imports (ServerEndpoint, onMessage, etc.) to the Tomcat-specific jakarta.websocket.* packages instead of the javax.websocket.x packages.
Here is the endpoint code that worked for me -- notice that there are no javax.websocket imports and instead I have jakarta.websocket imports:
import java.io.IOException;
import jakarta.websocket.EncodeException;
import jakarta.websocket.OnMessage;
import jakarta.websocket.Session;
import jakarta.websocket.server.ServerEndpoint;
#ServerEndpoint("/echo")
public class EchoEndpoint {
// Implementation.
#OnMessage
public void onMessage(
Session session,
String message)
throws
IOException,
EncodeException {
// Send the same message back.
session.getBasicRemote().sendText(message);
}
}
And my pom.xml file dependencies:
<!-- https://mvnrepository.com/artifact/org.apache.tomcat.embed/tomcat-embed-core -->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-core</artifactId>
<version>10.1.0-M8</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.tomcat.embed/tomcat-embed-websocket -->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-websocket</artifactId>
<version>10.1.0-M8</version>
</dependency>
As far as I can tell, the pom.xml should not contain the javax.websocket dependency at all, to ensure there are no collisions/clashes between that one and the Tomcat-specific tomcat-embed-websocket dependency.
I have a schedule service which gets its job via REST as JSON.
The Resource class:
import java.io.IOException;
import javax.inject.Inject;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.core.MediaType;
import de.fszm.scheduler.controller.SchedulerController;
import de.fszm.scheduler.entities.MySchedule;
#Path("/schedule")
public class ScheduleRESTResource {
#Inject
SchedulerController scheduleController;
#POST
#Path("/job")
#Consumes(MediaType.APPLICATION_JSON)
public void schedule(MySchedule schedule) throws IOException {
scheduleController.buildSchedule(schedule);
}
}
The ScheduleController:
import javax.enterprise.context.RequestScoped;
import javax.inject.Named;
import de.fszm.scheduler.entities.MySchedule;
#Named
#RequestScoped
public class SchedulerController {
public void buildSchedule(MySchedule schedule) {
System.out.println("Test");
}
}
The SchedulerMain:
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.wildfly.swarm.container.Container;
import org.wildfly.swarm.jaxrs.JAXRSArchive;
import de.fszm.scheduler.controller.SchedulerController;
import de.fszm.scheduler.entities.MySchedule;
import de.fszm.scheduler.rest.JaxRSActivator;
import de.fszm.scheduler.rest.ScheduleRESTResource;
public class SchedulerMain {
public static void main(String[] args) {
try {
Container container = new Container();
container.start();
JAXRSArchive appDeployment = ShrinkWrap.create(JAXRSArchive.class);
appDeployment.addResource(ScheduleRESTResource.class);
appDeployment.addResource(JaxRSActivator.class);
appDeployment.addClass(MySchedule.class);
appDeployment.addClass(SchedulerController.class);
appDeployment.addAllDependencies();
container.deploy(appDeployment);
} catch (Exception e) {
e.printStackTrace();
}
}
}
And the MySchedule ist just a POJO
My problem is that when I POST JSON to the I get a NullPointerException for the injected SchedulerController.
I also have a beans.xml in src/main/webapp/WEB-INF and in my pom.xml I have the following dependency for CDI (weld)
<dependency>
<groupId>org.wildfly.swarm</groupId>
<artifactId>weld</artifactId>
</dependency>
and
<dependency>
<groupId>javax.enterprise</groupId>
<artifactId>cdi-api</artifactId>
<version>1.2</version>
</dependency>
I am using WildFly swarm 1.0.0 beta 6
What did I miss?
I think you are missing the Swarm CDI fraction.
Try adding this to your dependencies instead.
<dependency>
<groupId>org.wildfly.swarm</groupId>
<artifactId>cdi</artifactId>
</dependency>