Spring Boot , Swagger - Unable to render this definition - spring-boot

Spring boot
In my build.gradle:
plugins {
id 'org.springframework.boot' version '2.2.2.RELEASE'
id 'io.spring.dependency-management' version '1.0.8.RELEASE'
id 'java' // jar not work with JSP
//id 'war' // to use JSP
}
group = 'com.myproject'
version = '1.0.2'
sourceCompatibility = '1.8'
processResources {
filesMatching('application.yml') {
expand(project.properties)
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'com.google.code.gson:gson:2.7'
implementation 'com.h2database:h2'
implementation 'javax.servlet:jstl:1.2'
implementation 'org.springframework.boot:spring-boot-devtools'
implementation 'org.springframework.boot:spring-boot-starter'
implementation 'org.springframework.boot:spring-boot-starter-actuator'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-jdbc'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-log4j2'
implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-yaml'
implementation 'com.squareup.okhttp3:logging-interceptor:3.8.0'
implementation('com.squareup.retrofit2:retrofit:2.4.0')
implementation('com.squareup.retrofit2:converter-gson:2.4.0')
compile group: 'io.springfox', name: 'springfox-swagger2', version: '2.9.2'
compile group: 'io.springfox', name: 'springfox-swagger-ui', version: '2.9.2'
testImplementation('org.springframework.boot:spring-boot-starter-test') {
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
}
testImplementation 'org.junit.jupiter:junit-jupiter:5.5.2'
}
configurations {
all {
exclude group: 'org.springframework.boot', module: 'spring-boot-starter-logging'
}
}
test {
useJUnitPlatform()
}
here application.yml
logging:
level:
org.hibernate.SQL: debug
# for Spring Actuator
management:
endpoints:
web:
exposure:
include: beans, env, info, health, metrics
server:
port: 8090
connection-timeout: 30000
spring:
application:
name: E-shop
version: ${version}
datasource:
url: jdbc:h2:file:./db/eshop.h2.db
username: sa
password:
driver-class-name: org.h2.Driver
jpa:
hibernate.ddl-auto: update
thymeleaf:
cache: false
enabled: true
prefix: classpath:/templates/
suffix: .html
h2: # default db. Open web page to H2 db -> http://localhost:8090/h2-console
console:
enabled: true
http:
converters:
preferred-json-mapper: gson
mvc:
view:
prefix: /WEB-INF/jsp/
suffix: .jsp
Here my security config:
#Configuration
#EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
private DataSource dataSource; // get by Spring
#Override
public void configure(HttpSecurity http) throws Exception {
http
.headers().frameOptions().sameOrigin()
.and()
.authorizeRequests()
// Here, you are making the public directory on the classpath root available without authentication (e..g. for css files)
.antMatchers("/public/**", "/registration.html").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login.html")
.successHandler((request, response, authentication) -> new DefaultRedirectStrategy().sendRedirect(request, response, "/index"))
.failureUrl("/login-error.html")
.permitAll()
.and()
.logout()
.logoutSuccessHandler(new CustomLogoutSuccessHandler())
.permitAll();
}
// login by user from db
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.jdbcAuthentication()
.dataSource(dataSource)
.passwordEncoder(NoOpPasswordEncoder.getInstance())
.usersByUsernameQuery("SELECT username, password, active FROM usr WHERE username=?")
.authoritiesByUsernameQuery("SELECT u.username, ur.role FROM usr u INNER JOIN user_roles ur ON u.id = ur.user_id WHERE u.username=?");
}
In my application:
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.context.annotation.Bean;
import org.springframework.core.task.TaskExecutor;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import java.util.Date;
#SpringBootApplication
#EnableAsync
#EnableSwagger2
public class EshopApplication {
Here my swagger config:
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 SwaggerFoxConfig {
#Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.any())
.paths(PathSelectors.any())
.build();
}
}
But when I try to start Swagger on address:
http://127.0.0.1:8090/swagger-ui.html
I get error:
Unable to render this definition
The provided definition does not specify a valid version field.
Please indicate a valid Swagger or OpenAPI version field. Supported version fields are swagger: "2.0" and those that match openapi: 3.0.n (for example, openapi: 3.0.0).

Add the following bean to your code:
#Configuration
#EnableSwagger2
public class SpringFoxConfig {
#Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.any())
.paths(PathSelectors.any())
.build();
}
}

I was facing same problem. In my case, the problem was some mistake in serialization using jackson X gson.
What I did: I added a converter to gson in the Swagger config class.
#Bean
public GsonHttpMessageConverter gsonHttpMessageConverter() {
GsonHttpMessageConverter converter = new GsonHttpMessageConverter();
converter.setGson(gson());
return converter;
}
private Gson gson() {
final GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(Json.class, new SpringfoxJsonToGsonAdapter());
return builder.create();
}
public class SpringfoxJsonToGsonAdapter implements JsonSerializer<Json> {
#Override
public JsonElement serialize(Json json, Type type, JsonSerializationContext context) {
return JsonParser.parseString(json.value());
}
}

Related

Spring Boot Kotlin Cannot Find Repository Beans

I'm just getting started with Spring Boot + Kotlin and I was trying out the PagingAndSortingRepository interface for JPA so I wrote the following interface:
interface CustomerRepository : PagingAndSortingRepository<Customer, Long>
The model for Customer is below:
#Entity
data class Customer(
#Id #GeneratedValue var id: Long,
var name: String
)
Now I'm trying to hook it up with a CustomerService which looks like this:
#Service
class CustomerService(
private val customerRepository: CustomerRepository
) {
fun getAllCustomers(): Collection<Customer> = customerRepository.findAll().toList()
fun addCustomer(customer: Customer) = customerRepository.save(customer)
fun deleteCustomer(customer: Customer) = customerRepository.delete(customer)
fun updateCustomer(customer: Customer) = customerRepository.save(customer)
}
And the Application looks like this:
#SpringBootApplication
#Configuration
#EnableAutoConfiguration
#EnableJpaRepositories
class Application
fun main(args: Array<String>) {
runApplication<Application>(*args)
}
I've added the required dependencies I believe, which are shown below:
plugins {
id("org.springframework.boot") version "2.5.0-SNAPSHOT"
id("io.spring.dependency-management") version "1.0.11.RELEASE"
kotlin("jvm") version "1.4.30"
kotlin("plugin.spring") version "1.4.30"
}
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
implementation("org.apache.derby:derby:10.15.2.0")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
implementation("org.jetbrains.kotlin:kotlin-reflect")
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
Spring Boot is not able to find a bean which sort of makes sense as I haven't defined one. However reading the documentation, it looks like one should be generated by Spring Boot here: Spring Boot Data Repositories
Application.properties is
spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
The error message I get is:
Description:
Parameter 0 of constructor in com.ubiquifydigital.crm.service.CustomerService required a bean named 'entityManagerFactory' that could not be found.
Action:
Consider defining a bean named 'entityManagerFactory' in your configuration.
I saw a few different posts regarding this and have tried adding the Configuration, AutoConfiguration and EnableJpaRepositories annotations however that has only changed the error to entityManagerFactory not found instead of the CustomerRepository not found.
When using default in-memory db you must define
spring.jpa.hibernate.ddl-auto=update
in application.properties as informed here. You are also missing #Autowired annotation. entityManagerFactory is missing because the default auo configuration is turned off, in that case application is expecting you to do all the necessary configuration which again you are not doing. So keep the default configuration on and change what you need.
This code is assumed in a single file.
If you are having multiple packages then you may need to add as mentioned in this link
Working code:
package com.example.demo
import com.fasterxml.jackson.annotation.JsonProperty
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.kotlin.KotlinModule
import lombok.*
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.context.annotation.Primary
import org.springframework.data.repository.CrudRepository
import org.springframework.stereotype.Repository
import org.springframework.web.bind.annotation.*
import java.util.*
import javax.persistence.Entity
import javax.persistence.GeneratedValue
import javax.persistence.Id
import javax.persistence.Table
#SpringBootApplication
open class SpringBootDerbyAppApplication
fun main(args: Array<String>) {
runApplication<SpringBootDerbyAppApplication>(*args)
}
#Entity
#Getter
#Setter
#AllArgsConstructor
#NoArgsConstructor
#Table(name = "applog")
internal class AppLog {
#Id
#GeneratedValue
private val id: Long = 0
#JsonProperty
private val name: String? = null
}
#Configuration
open class ObjectMapperConfiguration {
#Bean
#Primary
open fun objectMapper() = ObjectMapper().apply {
registerModule(KotlinModule())
}
}
#RestController
#RequestMapping(path = ["/logs"])
internal class LogController #Autowired constructor(private val appLogRepository: AppLogRepository) {
#GetMapping(path = ["/"])
fun logs(): MutableIterable<AppLog> {
return appLogRepository.findAll()
}
#PostMapping(path = ["/"])
fun add(#RequestBody appLog: AppLog): AppLog {
appLogRepository.save(appLog)
return appLog
}
}
#Repository
internal interface AppLogRepository : CrudRepository<AppLog, Long>
gradle file
plugins {
id 'org.springframework.boot' version '2.4.3'
id 'io.spring.dependency-management' version '1.0.11.RELEASE'
id 'java'
id 'org.jetbrains.kotlin.jvm' version '1.5.0-M1'
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
maven { url 'https://dl.bintray.com/kotlin/kotlin-eap' }
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-web'
compileOnly 'org.projectlombok:lombok'
runtimeOnly 'org.apache.derby:derby'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
implementation("org.jetbrains.kotlin:kotlin-reflect")
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
}
test {
useJUnitPlatform()
}
compileKotlin {
kotlinOptions {
jvmTarget = "1.8"
}
}
compileTestKotlin {
kotlinOptions {
jvmTarget = "1.8"
}
}

Spring security throwing 401 error with valid client id and client secret

I have a spring boot 2 app REST endpoint as below
#DeleteMapping(value = "/deleteUser", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity deleteUser(HttpServletRequest pRequest,
#RequestParam(value = "userId", required = true) String userId) {
if (validateRequest(userId)) {
try {
response = myService.deleteUser(userId);
} catch (Exception e) {
logger.error("Exception");
}
} else {
response = new ResponseEntity("Invalid user request.", new HttpHeaders(), HttpStatus.FORBIDDEN);
}
return response;
}
App doesnt have the basic auth enforced but restriction on endpoint.
Client is invoking the url with valid credentials:
deleteUserUrl=https://xxxx,clientId=xxxx,clentSecret=xxx
getting the error:
Full authentication is required to access this resource
here is my WebSecurityConfig file. This access is restricted to only certain role.
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSEALSecurityConfig
{
#Value("${ldap.server.admin.group}")
private String SERVER_ADMIN_GROUP;
#Value("${app.user.group}")
private String APP_GP_USER;
#Autowired
private AuthEntryPoint unauthorizedHandler;
//This class just to capture 401 error
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception
{
httpSecurity
.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
.antMatchers("/actuator/health").permitAll()
.antMatchers("/actuator/**").hasRole(SERVER_ADMIN_GROUP)
.antMatchers("/test/deleteUser").hasRole(APP_GP_USER)
.and().addFilterBefore(getCmpAuthenticationSelectionFilter(),
BasicAuthenticationFilter.class)
.httpBasic()
.authenticationEntryPoint(unauthorizedHandler)
.and().csrf().disable()
. sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
}
Here is my CORS filter class:
#Configuration
public class CORSConfig {
#Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
}
Here is my gradle file:
plugins {
id 'org.springframework.boot' version '2.1.6.RELEASE'
id 'java'
}
apply plugin: 'io.spring.dependency-management'
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'
apply plugin: 'jacoco'
apply plugin: 'checkstyle'
apply plugin: 'jdepend'
sourceCompatibility = 1.11
dependencies {
implementation('org.springframework.boot:spring-boot-starter')
compile('org.springframework.boot:spring-boot-starter-actuator')
compile('org.springframework.boot:spring-boot-starter-cache')
compile('org.springframework.boot:spring-boot-starter-web')
compile('org.springframework.boot:spring-boot-starter-mail')
implementation "com.company:webauth-plugin:2.0.1"
implementation('org.springframework.boot:spring-boot-starter-security')
compile('org.springframework.boot:spring-boot-starter-jdbc') {
exclude group: 'org.apache.tomcat', module: 'tomcat-jdbc'
}
compile('org.apache.commons:commons-lang3:3.5')
compile('org.springframework.boot:spring-boot-starter-data-jpa')
compile('org.apache.commons:commons-collections4:4.0')
compile group: 'net.minidev', name: 'json-smart', version: '1.0.9'
compile group: 'net.sf.jt400', name: 'jt400-jdk8', version: '9.5'
compile('org.apache.httpcomponents:httpclient:4.3.4')
compileOnly 'org.projectlombok:lombok'
runtime('com.microsoft:sqljdbc4:4.0')
testCompile group: 'org.springframework.boot', name: 'spring-boot-starter-test'
testCompile group: 'junit', name: 'junit'
}
application.properties file:
app.environment=${APP_ENV}
server.servlet.context-path=${SERVER_CONTEXT_PATH}
server.port=${SERVER_PORT}
management.endpoints.web.exposure.include=*
management.endpoint.shutdown.enabled=true
management.health.ldap.enabled=false
management.endpoints.web.cors.allow-credentials=true
Please note: This stopped working after made below changes in the app:
Introduction of CORSConfig class
Removing the gradle dependency
compile group: 'org.springframework.security', name: 'spring-security-ldap', version: '5.1.2.RELEASE'
Included AuthEntryPoint class to capture 401 error
Please advice what I am doing wrong here, thanks in advance
You are getting a 401 error. That means the url you are trying to access is protected. Since, you are saying you have provided valid user credentails, then maybe the user does not have the role "APP_GP_USER"?
I see that you are passing in sensitive information like client id/client secret as part of the request url. You should probably re-look at that.
Is the client passing in the Authorization header in the delete request? You need to provide this as you have enabled basic authentication in your WebSecurityConfig file through httpBasic() in the configure method.
I would suggest you to test your urls using a http client like postman.
For example, here I am trying to access a protected url: http://localhost:8088/demo/home without providing basic auth. Notice, I get a 401 error.
401 error
And here, I have provided proper credentials and so get back a proper response. Notice how postman added the Authorization header.
Added basic auth
Success response

Spring Security 5 with JDBC Authentication: UserDetailsService bean is still in-memory rather than JDBC

I'm building a Spring Security sample with JDBC authentication using Spring Boot and Kotlin. I've configured the JDBC authentication like in the documentation (https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#jc-authentication-jdbc):
#EnableWebSecurity
class SecurityConfig {
#Autowired
fun configureGlobal(
auth: AuthenticationManagerBuilder,
dataSource: DataSource
) {
auth
.jdbcAuthentication()
.withDefaultSchema()
.dataSource(dataSource)
.withUser(User.withDefaultPasswordEncoder()
.username("alice")
.password("password")
.roles("USER"))
}
}
It's not clear why Spring Security still keeps InMemory UserDetailsService implementation? Line (1) below throws UsernameNotFoundException if uncommented because default UserDetailsService bean in Spring Context is InMemory implementation rather than JDBC that I just configured. It would be OK if InMemory one returned users that configured above, but it doesn't.
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
import org.springframework.security.authentication.ProviderManager
import org.springframework.security.authentication.dao.DaoAuthenticationProvider
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration
import org.springframework.security.core.userdetails.UserDetailsService
#SpringBootApplication
class JdbcAuthenticationSampleApplication
fun main(args: Array<String>) {
val context = runApplication<JdbcAuthenticationSampleApplication>(*args)
// default UserDetailsService bean is still InMemory implementation
val defaultUserDetailsService = context.getBean(UserDetailsService::class.java)
println("Default UserDetailsService: $defaultUserDetailsService")
// "alice" can't be found by it and it throws UsernameNotFoundException
//defaultUserDetailsService.loadUserByUsername("alice") // (1)
// I could get JDBC UserDetailsService only by this improper way
val authenticationConfiguration = context.getBean(AuthenticationConfiguration::class.java)
val authenticationManager = authenticationConfiguration.authenticationManager as ProviderManager
val authenticationProvider = authenticationManager.providers[0] as DaoAuthenticationProvider
val getUserDetailsService = DaoAuthenticationProvider::class.java.getDeclaredMethod("getUserDetailsService")
getUserDetailsService.isAccessible = true
val jdbcUserDetailsService = getUserDetailsService.invoke(authenticationProvider) as UserDetailsService
println("JDBC UserDetailsService: $jdbcUserDetailsService")
// should find "alice" now
println("User: ${jdbcUserDetailsService.loadUserByUsername("alice")}")
context.close()
}
and the output is:
Default UserDetailsService: org.springframework.security.provisioning.InMemoryUserDetailsManager#6af87130
JDBC UserDetailsService: org.springframework.security.provisioning.JdbcUserDetailsManager#22a4ca4a
User: org.springframework.security.core.userdetails.User#5899680: Username: alice; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_USER
And here's my build.gradle.kts for clarity, pretty standard. No more configuration other than this.
plugins {
id("org.springframework.boot") version "2.2.4.RELEASE"
id("io.spring.dependency-management") version "1.0.9.RELEASE"
kotlin("jvm") version "1.3.61"
kotlin("plugin.spring") version "1.3.61"
}
group = "sample.spring.security"
version = "0.0.1-SNAPSHOT"
java.sourceCompatibility = JavaVersion.VERSION_1_8
repositories {
mavenCentral()
}
dependencies {
implementation("org.springframework.boot:spring-boot-starter-data-jdbc")
implementation("org.springframework.boot:spring-boot-starter-security")
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
implementation("org.jetbrains.kotlin:kotlin-reflect")
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
runtimeOnly("com.h2database:h2")
testImplementation("org.springframework.boot:spring-boot-starter-test") {
exclude(group = "org.junit.vintage", module = "junit-vintage-engine")
}
testImplementation("org.springframework.security:spring-security-test")
}
Here is the test that can't even start due to UsernameNotFoundException:
#SpringBootTest
#AutoConfigureTestDatabase
class JdbcAuthenticationSampleApplicationTests #Autowired constructor(
val userDetailsService: UserDetailsService
) {
#Test
#WithUserDetails("alice")
fun testUserDetailsService() {
//SecurityContext can't be built due to UsernameNotFoundException
}
}
The question is why there is still in-memory UserDetailService? And how can I get JDBC UserDetailsService properly?
It's worth to mention that JDBC authentication works correct when the user authenticates through log on form on UI.
The method jdbcAuthentication ensures that a UserDetailsService is available for the AuthenticationManagerBuilder.getDefaultUserDetailsService() method.
That is why your application is working as expected when a user authenticates through the UI.
However, it does not create a UserDetailsService bean.
Using context.getBean() and #WithUserDetails both expect a UserDetailsService bean.
If you want to continue to configure jdbcAuthentication as above, then you can use something like #WithMockUser in you tests.
Alternatively, if you want to create a UserDetailsService bean, you can do so with the following configuration, which is similar to your configuration above.
You will need to modify the DataSource bean. This example simply illustrates how to use the default schema.
#Bean
fun dataSource(): DataSource {
return EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.H2)
.addScript("classpath:org/springframework/security/core/userdetails/jdbc/users.ddl")
.build()
}
#Bean
fun users(dataSource: DataSource): UserDetailsManager {
val userDetailsManager = JdbcUserDetailsManager(dataSource)
userDetailsManager.createUser(User.withDefaultPasswordEncoder()
.username("alice")
.password("password")
.roles("USER")
.build())
return userDetailsManager
}
Alternatively, UserDetailsService bean can be taken from just configured jdbcAuthentication(), in addition to my original SecurityConfig:
#Bean
fun userDetailsService(auth: AuthenticationManagerBuilder): UserDetailsService = auth.defaultUserDetailsService
It's shorter and is instantiated in proper order - after #Autowired fun configureGlobal(...) because SecurityConfig, as a bean, itself is initialized before the beans declared inside it.
Full config:
#EnableWebSecurity
class SecurityConfig {
#Bean
fun userDetailsService(auth: AuthenticationManagerBuilder): UserDetailsService = auth.defaultUserDetailsService
#Autowired
fun configureGlobal(auth: AuthenticationManagerBuilder,
dataSource: DataSource) {
auth.jdbcAuthentication()
.withDefaultSchema()
.dataSource(dataSource)
.withUser(User.withDefaultPasswordEncoder()
.username("alice")
.password("password")
.roles("USER"))
}
}

Dependencies for Spring Integration Amqp in Spring Boot

In order to use Spring Integration Amqp in a Spring Boot application, what are the dependencies I need to include?
Spring Boot version is 2.0.5.
Current dependencies I have are spring-boot-starter-integration and spring-integration-amqp
Error messages are classes like SimpleMessageListenerContainer and AmqpInboundChannelAdapter are not found on the classpath.
UPDATE:
My build.gradle entries --
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:2.0.5.RELEASE")
}
}
dependencies {
compile('org.springframework.boot:spring-boot-starter-integration')
compile('org.springframework.boot:spring-boot-starter-amqp')
compile('org.springframework.integration:spring-integration-amqp')
testCompile('org.springframework.boot:spring-boot-starter-test')
}
I had to add the following dependencies to resolve the classes in question (the last in the list did it, using latest spring initalizr, spring-boot 2.0.5)
dependencies {
implementation('org.springframework.boot:spring-boot-starter-amqp')
implementation('org.springframework.boot:spring-boot-starter-integration')
testImplementation('org.springframework.boot:spring-boot-starter-test')
compile 'org.springframework.integration:spring-integration-amqp'
}
To be fair, this answer was already given, just not for gradle.
I am using gradle 4.10.2 on a linux machine, spring-boot initialzr with the options RabbitMQ and Spring-Integration. Here are the changed files:
build.gradle
buildscript {
ext {
springBootVersion = '2.0.5.RELEASE'
}
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8
repositories {
mavenCentral()
}
dependencies {
implementation('org.springframework.boot:spring-boot-starter-amqp')
implementation('org.springframework.boot:spring-boot-starter-integration')
testImplementation('org.springframework.boot:spring-boot-starter-test')
compile 'org.springframework.integration:spring-integration-amqp'
}
Implementation of Example 12.2.1 Configuring with Java Configuration from the Spring Integration docs:
package com.example.integrationamqp;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.integration.amqp.inbound.AmqpInboundChannelAdapter;
import org.springframework.integration.amqp.inbound.AmqpInboundGateway;
import org.springframework.integration.annotation.ServiceActivator;
import org.springframework.integration.channel.DirectChannel;
import org.springframework.integration.handler.AbstractReplyProducingMessageHandler;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.MessageHandler;
import org.springframework.messaging.MessagingException;
#SpringBootApplication
public class IntegrationAmqpApplication {
public static void main(String[] args) {
new SpringApplicationBuilder(IntegrationAmqpApplication.class)
.web(WebApplicationType.NONE)
.run(args);
}
#Bean
public MessageChannel amqpInputChannel() {
return new DirectChannel();
}
#Bean
public AmqpInboundChannelAdapter inbound(SimpleMessageListenerContainer listenerContainer,
#Qualifier("amqpInputChannel") MessageChannel channel) {
AmqpInboundChannelAdapter adapter = new AmqpInboundChannelAdapter(listenerContainer);
adapter.setOutputChannel(channel);
return adapter;
}
#Bean
public SimpleMessageListenerContainer container(ConnectionFactory connectionFactory) {
SimpleMessageListenerContainer container =
new SimpleMessageListenerContainer(connectionFactory);
container.setQueueNames("foo");
container.setConcurrentConsumers(2);
// ...
return container;
}
#Bean
#ServiceActivator(inputChannel = "amqpInputChannel")
public MessageHandler handler() {
return new MessageHandler() {
#Override
public void handleMessage(Message<?> message) throws MessagingException {
System.out.println(message.getPayload());
}
};
}
}
Add this dependency:
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
And are you sure you have this one?:
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-amqp</artifactId>

Angular CLI with Spring Boot

I have 2 projects. An Angular2 app which I build with Angular-cli and a Spring Boot app which will only serve the Angular2 app. I build the Angular2 app with ng build which generates a dist folder. I then put the content of the dist folder in the Spring Boot app inside src/main/resources/static.
My spring boot app has two files.
The Spring boot application class :
#SpringBootApplication
public class SpringBoot extends SpringBootServletInitializer {
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(SpringBoot.class);
}
public static void main(String[] args) throws Exception {
SpringApplication.run(SpringBoot.class, args);
}
}
And the application.properties file:
server.contextPath=/
server.port=80
It works well but if I go to an url and hit the refresh button, I get the Whitelabel Error Page. I know it's because the URLs are not serving the index.html when they don't match a resource file.
How can I configure my Spring Boot app to serve index.html if the url doesn't match a resource file?
You are correct that index.html needs to be served back for endpoints unknown to Spring. Then arrange for the Angular app to manage unknown routes.
I handle this situation with a WebMvcConfigurerAdapter. Also put static content file types in here.
Add a config directory and in it add a Java file WebMvcConfig (for example) with this content:
package com.yourdomain.yourapp.config;
import org.springframework.boot.autoconfigure.web.ResourceProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.resource.PathResourceResolver;
import java.io.IOException;
import javax.inject.Inject;
#Configuration
#EnableConfigurationProperties({ ResourceProperties.class })
public class WebMvcConfig extends WebMvcConfigurerAdapter {
#Inject
private ResourceProperties resourceProperties = new ResourceProperties();
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
Integer cachePeriod = resourceProperties.getCachePeriod();
final String[] staticLocations = resourceProperties.getStaticLocations();
final String[] indexLocations = new String[staticLocations.length];
for (int i = 0; i < staticLocations.length; i++) {
indexLocations[i] = staticLocations[i] + "index.html";
}
registry.addResourceHandler(
"/**/*.css",
"/**/*.html",
"/**/*.js",
"/**/*.json",
"/**/*.bmp",
"/**/*.jpeg",
"/**/*.jpg",
"/**/*.gif",
"/**/*.ico",
"/**/*.png",
"/**/*.ttf",
"/**/*.wav",
"/**/*.mp3",
"/**/*.eot",
"/**/*.svg",
"/**/*.woff",
"/**/*.woff2",
"/**/*.map"
)
.addResourceLocations(staticLocations)
.setCachePeriod(cachePeriod);
registry.addResourceHandler("/**")
.addResourceLocations(indexLocations)
.setCachePeriod(cachePeriod)
.resourceChain(true)
.addResolver(new PathResourceResolver() {
#Override
protected Resource getResource(String resourcePath, Resource location) throws IOException {
return location.exists() && location.isReadable() ? location : null;
}
});
}
}
I think you will also have to specify the config package for component scan. Maybe try without first and see if it works.
#SpringBootApplication
#ComponentScan( basePackages = { "com.yourdomain.yourapp.config" })
public class SpringBoot extends SpringBootServletInitializer {
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(SpringBoot.class);
}
public static void main(String[] args) throws Exception {
SpringApplication.run(SpringBoot.class, args);
}
}
In case your missing dependencies. This is what I have in my build.gradle:
dependencies {
compile group: 'org.springframework.boot', name: 'spring-boot-starter-web'
compile group: 'javax.inject', name: 'javax.inject', version: '1'
optional group: 'org.springframework.boot', name: 'spring-boot-configuration-processor'
providedRuntime group: 'org.springframework.boot', name: 'spring-boot-starter-tomcat'
testCompile group: 'org.springframework.boot', name: 'spring-boot-starter-test'
}
Hope this helps :-)
Here you can find my Spring Boot 2 and Angular 6 starter project.
Spring Boot application is created using SPRING INITIALIZR, Angular application is created using Angular CLI.

Resources