Merge branch 'master' into BAEL-20873-move-spring-boot-kotlin

This commit is contained in:
Loredana Crusoveanu
2020-01-29 22:16:05 +02:00
committed by GitHub
324 changed files with 2324 additions and 910 deletions
+6
View File
@@ -14,8 +14,14 @@
</parent>
<modules>
<module>spring-boot-artifacts</module>
<module>spring-boot-data</module>
<module>spring-boot-keycloak</module>
<module>spring-boot-kotlin</module>
<module>spring-boot-mvc-birt</module>
<module>spring-boot-properties</module>
<module>spring-boot-springdoc</module>
<module>spring-boot-testing</module>
<module>spring-boot-vue</module>
</modules>
@@ -0,0 +1,11 @@
## Spring Boot Artifacts
This module contains articles about configuring the Spring Boot build process.
### Relevant Articles:
- [Spring Boot Dependency Management with a Custom Parent](https://www.baeldung.com/spring-boot-dependency-management-custom-parent)
- [Create a Fat Jar App with Spring Boot](https://www.baeldung.com/deployable-fat-jar-spring-boot)
- [Intro to Spring Boot Starters](https://www.baeldung.com/spring-boot-starters)
- [Introduction to WebJars](https://www.baeldung.com/maven-webjars)
- [A Quick Guide to Maven Wrapper](https://www.baeldung.com/maven-wrapper)
- [Running a Spring Boot App with Maven vs an Executable War/Jar](https://www.baeldung.com/spring-boot-run-maven-vs-executable-jar)
@@ -0,0 +1,194 @@
<?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>
<artifactId>spring-boot-artifacts</artifactId>
<name>spring-boot-artifacts</name>
<packaging>war</packaging>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>com.baeldung</groupId>
<artifactId>parent-boot-2</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../../parent-boot-2</relativePath>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>javax.persistence</groupId>
<artifactId>javax.persistence-api</artifactId>
<version>${jpa.version}</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>${guava.version}</version>
</dependency>
<dependency>
<groupId>org.subethamail</groupId>
<artifactId>subethasmtp</artifactId>
<version>${subethasmtp.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>bootstrap</artifactId>
<version>${bootstrap.version}</version>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>${jquery.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-context</artifactId>
<version>${springcloud.version}</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>${httpclient.version}</version>
</dependency>
</dependencies>
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
<configuration>
<mainClass>com.baeldung.webjar.WebjarsdemoApplication</mainClass>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.18</version>
<executions>
<!-- Invokes both the integration-test and the verify goals of the Failsafe
Maven plugin -->
<execution>
<id>integration-tests</id>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
<configuration>
<!-- Skips integration tests if the value of skip.integration.tests
property is true -->
<includes>
<include>**/ExternalPropertyFileLoaderIntegrationTest.java</include>
</includes>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>autoconfiguration</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<executions>
<execution>
<phase>integration-test</phase>
<goals>
<goal>test</goal>
</goals>
<configuration>
<excludes>
<exclude>**/*LiveTest.java</exclude>
<exclude>**/*IntegrationTest.java</exclude>
<exclude>**/*IntTest.java</exclude>
</excludes>
<includes>
<include>**/AutoconfigurationTest.java</include>
</includes>
</configuration>
</execution>
</executions>
<configuration>
<systemPropertyVariables>
<test.mime>json</test.mime>
</systemPropertyVariables>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<properties>
<!-- The main class to start by executing java -jar -->
<start-class>org.baeldung.boot.Application</start-class>
<jquery.version>3.1.1</jquery.version>
<bootstrap.version>3.3.7-1</bootstrap.version>
<jpa.version>2.2</jpa.version>
<guava.version>18.0</guava.version>
<subethasmtp.version>3.1.7</subethasmtp.version>
<springcloud.version>2.0.2.RELEASE</springcloud.version>
<httpclient.version>4.5.8</httpclient.version>
</properties>
</project>
@@ -0,0 +1,15 @@
package com.baeldung.webjar;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class TestController {
@GetMapping(value = "/")
public String welcome(Model model) {
return "index";
}
}
@@ -0,0 +1,12 @@
package com.baeldung.webjar;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class WebjarsdemoApplication {
public static void main(String[] args) {
SpringApplication.run(WebjarsdemoApplication.class, args);
}
}
@@ -0,0 +1 @@
spring.main.allow-bean-definition-overriding=true
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="STDOUT" />
</root>
</configuration>
@@ -0,0 +1,19 @@
<html>
<head>
<title>WebJars Demo</title>
<link rel="stylesheet" href="/webjars/bootstrap/3.3.7-1/css/bootstrap.min.css" />
</head>
<body>
<h1>Welcome Home</h1>
<div class="container"><br/>
<div class="alert alert-success">
<a href="#" class="close" data-dismiss="alert" aria-label="close">×</a>
<strong>Success!</strong> It is working as we expected.
</div>
</div>
<script src="/webjars/jquery/3.1.1/jquery.min.js"></script>
<script src="/webjars/bootstrap/3.3.7-1/js/bootstrap.min.js"></script>
</body>
</html>
@@ -0,0 +1,18 @@
package com.baeldung.webjar;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = WebjarsdemoApplication.class)
@WebAppConfiguration
public class WebjarsdemoApplicationIntegrationTest {
@Test
public void contextLoads() {
}
}
@@ -0,0 +1,11 @@
## Spring Boot Data
This module contains articles about Spring Boot with Spring Data
## Relevant Articles:
- [Formatting JSON Dates in Spring Boot](https://www.baeldung.com/spring-boot-formatting-json-dates)
- [Rendering Exceptions in JSON with Spring](https://www.baeldung.com/spring-exceptions-json)
- [Disable Spring Data Auto Configuration](https://www.baeldung.com/spring-data-disable-auto-config)
- [Repositories with Multiple Spring Data Modules](https://www.baeldung.com/spring-multiple-data-modules)
- [Spring Custom Property Editor](https://www.baeldung.com/spring-mvc-custom-property-editor)
@@ -0,0 +1,175 @@
<?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>
<artifactId>spring-boot-data</artifactId>
<name>spring-boot-data</name>
<packaging>war</packaging>
<description>Spring Boot Data Module</description>
<parent>
<groupId>com.baeldung</groupId>
<artifactId>parent-boot-2</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../../parent-boot-2</relativePath>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.javers</groupId>
<artifactId>javers-spring-boot-starter-sql</artifactId>
<version>${javers.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>${h2.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<finalName>spring-boot-data</finalName>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
</plugin>
<plugin>
<groupId>pl.project13.maven</groupId>
<artifactId>git-commit-id-plugin</artifactId>
<version>${git-commit-id-plugin.version}</version>
<executions>
<execution>
<id>get-the-git-infos</id>
<goals>
<goal>revision</goal>
</goals>
<phase>initialize</phase>
</execution>
<execution>
<id>validate-the-git-infos</id>
<goals>
<goal>validateRevision</goal>
</goals>
<phase>package</phase>
</execution>
</executions>
<configuration>
<generateGitPropertiesFile>true</generateGitPropertiesFile>
<generateGitPropertiesFilename>${project.build.outputDirectory}/git.properties
</generateGitPropertiesFilename>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${source.version}</source>
<target>${target.version}</target>
</configuration>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>autoconfiguration</id>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>com.baeldung.javers.SpringBootJaVersApplication</mainClass>
<layout>JAR</layout>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${source.version}</source>
<target>${target.version}</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<executions>
<execution>
<phase>integration-test</phase>
<goals>
<goal>test</goal>
</goals>
<configuration>
<excludes>
<exclude>**/*LiveTest.java</exclude>
<exclude>**/*IntegrationTest.java</exclude>
<exclude>**/*IntTest.java</exclude>
</excludes>
<includes>
<include>**/AutoconfigurationTest.java</include>
</includes>
</configuration>
</execution>
</executions>
<configuration>
<systemPropertyVariables>
<test.mime>json</test.mime>
</systemPropertyVariables>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${source.version}</source>
<target>${target.version}</target>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<properties>
<javers.version>5.6.3</javers.version>
<git-commit-id-plugin.version>2.2.4</git-commit-id-plugin.version>
<source.version>1.8</source.version>
<target.version>1.8</target.version>
</properties>
</project>
@@ -0,0 +1,13 @@
package com.baeldung;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringBootDataApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootDataApplication.class, args);
}
}
@@ -0,0 +1,19 @@
package com.baeldung.disableautoconfig;
import org.javers.spring.boot.sql.JaversSqlAutoConfiguration;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class,
JaversSqlAutoConfiguration.class, SpringDataWebAutoConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class, HibernateJpaAutoConfiguration.class})
public class SpringDataJPA {
public static void main(String[] args) {
SpringApplication.run(SpringDataJPA.class, args);
}
}
@@ -0,0 +1,16 @@
package com.baeldung.disableautoconfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration;
import org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration;
import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration;
@SpringBootApplication(exclude = {MongoAutoConfiguration.class, MongoDataAutoConfiguration.class,
SpringDataWebAutoConfiguration.class})
public class SpringDataMongoDB {
public static void main(String[] args) {
SpringApplication.run(SpringDataMongoDB.class, args);
}
}
@@ -0,0 +1,16 @@
package com.baeldung.disableautoconfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
import org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration;
import org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration;
@SpringBootApplication(exclude = {RedisAutoConfiguration.class, RedisRepositoriesAutoConfiguration.class,
SpringDataWebAutoConfiguration.class})
public class SpringDataRedis {
public static void main(String[] args) {
SpringApplication.run(SpringDataRedis.class, args);
}
}
@@ -0,0 +1,3 @@
### Relevant Articles
- [Using JaVers for Data Model Auditing in Spring Data](https://www.baeldung.com/spring-data-javers-audit)
@@ -0,0 +1,31 @@
package com.baeldung.javers;
import com.baeldung.javers.domain.Address;
import com.baeldung.javers.domain.Product;
import com.baeldung.javers.domain.Store;
import com.baeldung.javers.repo.StoreRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;
@SpringBootApplication
public class SpringBootJaVersApplication {
@Autowired
StoreRepository storeRepository;
public static void main(String[] args) {
SpringApplication.run(SpringBootJaVersApplication.class, args);
}
@EventListener
public void appReady(ApplicationReadyEvent event) {
Store store = new Store("Baeldung store", new Address("Some street", 22222));
for (int i = 1; i < 3; i++) {
Product product = new Product("Product #" + i, 100 * i);
store.addProduct(product);
}
storeRepository.save(store);
}
}
@@ -0,0 +1,20 @@
package com.baeldung.javers.config;
import org.javers.spring.auditable.AuthorProvider;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class JaversConfiguration {
@Bean
public AuthorProvider provideJaversAuthor() {
return new SimpleAuthorProvider();
}
private static class SimpleAuthorProvider implements AuthorProvider {
@Override
public String provide() {
return "Baeldung Author";
}
}
}
@@ -0,0 +1,33 @@
package com.baeldung.javers.domain;
import javax.persistence.Embeddable;
@Embeddable
public class Address {
private String address;
private Integer zipCode;
public Address(String address, Integer zipCode) {
this.address = address;
this.zipCode = zipCode;
}
public Address() {
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public Integer getZipCode() {
return zipCode;
}
public void setZipCode(Integer zipCode) {
this.zipCode = zipCode;
}
}
@@ -0,0 +1,61 @@
package com.baeldung.javers.domain;
import javax.persistence.*;
@Entity
public class Product {
@Id
@GeneratedValue
private int id;
private String name;
private double price;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "store_id")
private Store store;
public Product(String name, double price) {
this.name = name;
this.price = price;
}
public Product() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public Store getStore() {
return store;
}
public void setStore(Store store) {
this.store = store;
}
public void setNamePrefix(String prefix) {
this.name = prefix + this.name;
}
}
@@ -0,0 +1,62 @@
package com.baeldung.javers.domain;
import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;
@Entity
public class Store {
@Id
@GeneratedValue
private int id;
private String name;
@Embedded
private Address address;
@OneToMany(
mappedBy = "store",
cascade = CascadeType.ALL,
orphanRemoval = true
)
private List<Product> products = new ArrayList<>();
public Store(String name, Address address) {
this.name = name;
this.address = address;
}
public Store() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public void addProduct(Product product) {
product.setStore(this);
this.products.add(product);
}
public List<Product> getProducts() {
return this.products;
}
}
@@ -0,0 +1,11 @@
package com.baeldung.javers.repo;
import com.baeldung.javers.domain.Product;
import org.javers.spring.annotation.JaversAuditable;
import org.springframework.data.repository.CrudRepository;
public interface ProductRepository extends CrudRepository<Product, Integer> {
@Override
@JaversAuditable
<S extends Product> S save(S s);
}
@@ -0,0 +1,9 @@
package com.baeldung.javers.repo;
import com.baeldung.javers.domain.Store;
import org.javers.spring.annotation.JaversSpringDataAuditable;
import org.springframework.data.repository.CrudRepository;
@JaversSpringDataAuditable
public interface StoreRepository extends CrudRepository<Store, Integer> {
}
@@ -0,0 +1,59 @@
package com.baeldung.javers.service;
import com.baeldung.javers.domain.Product;
import com.baeldung.javers.domain.Store;
import com.baeldung.javers.repo.ProductRepository;
import com.baeldung.javers.repo.StoreRepository;
import org.springframework.stereotype.Service;
import java.util.Optional;
import java.util.Random;
@Service
public class StoreService {
private final ProductRepository productRepository;
private final StoreRepository storeRepository;
public StoreService(ProductRepository productRepository, StoreRepository storeRepository) {
this.productRepository = productRepository;
this.storeRepository = storeRepository;
}
public void updateProductPrice(Integer productId, Double price) {
Optional<Product> productOpt = productRepository.findById(productId);
productOpt.ifPresent(product -> {
product.setPrice(price);
productRepository.save(product);
});
}
public void rebrandStore(int storeId, String updatedName) {
Optional<Store> storeOpt = storeRepository.findById(storeId);
storeOpt.ifPresent(store -> {
store.setName(updatedName);
store.getProducts().forEach(product -> {
product.setNamePrefix(updatedName);
});
storeRepository.save(store);
});
}
public void createRandomProduct(Integer storeId) {
Optional<Store> storeOpt = this.storeRepository.findById(storeId);
storeOpt.ifPresent(store -> {
Random random = new Random();
Product product = new Product("Product#" + random.nextInt(), random.nextDouble() * 100);
store.addProduct(product);
storeRepository.save(store);
});
}
public Store findStoreById(int storeId) {
return storeRepository.findById(storeId).get();
}
public Product findProductById(int id) {
return this.productRepository.findById(id).get();
}
}
@@ -0,0 +1,5 @@
package com.baeldung.javers.web;
public class RebrandStoreDto {
public String name;
}
@@ -0,0 +1,73 @@
package com.baeldung.javers.web;
import com.baeldung.javers.domain.Product;
import com.baeldung.javers.domain.Store;
import com.baeldung.javers.service.StoreService;
import org.javers.core.Changes;
import org.javers.core.Javers;
import org.javers.core.metamodel.object.CdoSnapshot;
import org.javers.repository.jql.JqlQuery;
import org.javers.repository.jql.QueryBuilder;
import org.javers.shadow.Shadow;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
public class StoreController {
private final StoreService storeService;
private final Javers javers;
public StoreController(StoreService customerService, Javers javers) {
this.storeService = customerService;
this.javers = javers;
}
@PostMapping("/stores/{storeId}/products/random")
public void createRandomProduct(@PathVariable final Integer storeId) {
storeService.createRandomProduct(storeId);
}
@PostMapping("/stores/{storeId}/rebrand")
public void rebrandStore(@PathVariable final Integer storeId, @RequestBody RebrandStoreDto rebrandStoreDto) {
storeService.rebrandStore(storeId, rebrandStoreDto.name);
}
@PostMapping(value = "/stores/{storeId}/products/{productId}/price", consumes = MediaType.APPLICATION_JSON_VALUE)
public void updateProductPrice(@PathVariable final Integer productId, @PathVariable String storeId, @RequestBody UpdatePriceDto priceDto) {
storeService.updateProductPrice(productId, priceDto.price);
}
@GetMapping("/products/{productId}/changes")
public String getProductChanges(@PathVariable int productId) {
Product product = storeService.findProductById(productId);
QueryBuilder jqlQuery = QueryBuilder.byInstance(product);
Changes changes = javers.findChanges(jqlQuery.build());
return javers.getJsonConverter().toJson(changes);
}
@GetMapping("/products/snapshots")
public String getProductSnapshots() {
QueryBuilder jqlQuery = QueryBuilder.byClass(Product.class);
List<CdoSnapshot> snapshots = javers.findSnapshots(jqlQuery.build());
return javers.getJsonConverter().toJson(snapshots);
}
@GetMapping("/stores/{storeId}/shadows")
public String getStoreShadows(@PathVariable int storeId) {
Store store = storeService.findStoreById(storeId);
JqlQuery jqlQuery = QueryBuilder.byInstance(store)
.withChildValueObjects().build();
List<Shadow<Store>> shadows = javers.findShadows(jqlQuery);
return javers.getJsonConverter().toJson(shadows.get(0));
}
@GetMapping("/stores/snapshots")
public String getStoresSnapshots() {
QueryBuilder jqlQuery = QueryBuilder.byClass(Store.class);
List<CdoSnapshot> snapshots = javers.findSnapshots(jqlQuery.build());
return javers.getJsonConverter().toJson(snapshots);
}
}
@@ -0,0 +1,5 @@
package com.baeldung.javers.web;
public class UpdatePriceDto {
public double price;
}
@@ -0,0 +1,70 @@
package com.baeldung.jsondateformat;
import com.fasterxml.jackson.annotation.JsonFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
public class Contact {
private String name;
private String address;
private String phone;
@JsonFormat(pattern="yyyy-MM-dd")
private LocalDate birthday;
@JsonFormat(pattern="yyyy-MM-dd HH:mm:ss")
private LocalDateTime lastUpdate;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public LocalDate getBirthday() {
return birthday;
}
public void setBirthday(LocalDate birthday) {
this.birthday = birthday;
}
public LocalDateTime getLastUpdate() {
return lastUpdate;
}
public void setLastUpdate(LocalDateTime lastUpdate) {
this.lastUpdate = lastUpdate;
}
public Contact() {
}
public Contact(String name, String address, String phone, LocalDate birthday, LocalDateTime lastUpdate) {
this.name = name;
this.address = address;
this.phone = phone;
this.birthday = birthday;
this.lastUpdate = lastUpdate;
}
}
@@ -0,0 +1,13 @@
package com.baeldung.jsondateformat;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ContactApp {
public static void main(String[] args) {
SpringApplication.run(ContactApp.class, args);
}
}
@@ -0,0 +1,33 @@
package com.baeldung.jsondateformat;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import java.time.format.DateTimeFormatter;
@Configuration
public class ContactAppConfig {
private static final String dateFormat = "yyyy-MM-dd";
private static final String dateTimeFormat = "yyyy-MM-dd HH:mm:ss";
@Bean
@ConditionalOnProperty(value = "spring.jackson.date-format", matchIfMissing = true, havingValue = "none")
public Jackson2ObjectMapperBuilderCustomizer jsonCustomizer() {
return new Jackson2ObjectMapperBuilderCustomizer() {
@Override
public void customize(Jackson2ObjectMapperBuilder builder) {
builder.simpleDateFormat(dateTimeFormat);
builder.serializers(new LocalDateSerializer(DateTimeFormatter.ofPattern(dateFormat)));
builder.serializers(new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(dateTimeFormat)));
}
};
}
}
@@ -0,0 +1,77 @@
package com.baeldung.jsondateformat;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@RestController
@RequestMapping(value = "/contacts")
public class ContactController {
@GetMapping
public List<Contact> getContacts() {
List<Contact> contacts = new ArrayList<>();
Contact contact1 = new Contact("John Doe", "123 Sesame Street", "123-456-789", LocalDate.now(), LocalDateTime.now());
Contact contact2 = new Contact("John Doe 2", "124 Sesame Street", "123-456-789", LocalDate.now(), LocalDateTime.now());
Contact contact3 = new Contact("John Doe 3", "125 Sesame Street", "123-456-789", LocalDate.now(), LocalDateTime.now());
contacts.add(contact1);
contacts.add(contact2);
contacts.add(contact3);
return contacts;
}
@GetMapping("/javaUtilDate")
public List<ContactWithJavaUtilDate> getContactsWithJavaUtilDate() {
List<ContactWithJavaUtilDate> contacts = new ArrayList<>();
ContactWithJavaUtilDate contact1 = new ContactWithJavaUtilDate("John Doe", "123 Sesame Street", "123-456-789", new Date(), new Date());
ContactWithJavaUtilDate contact2 = new ContactWithJavaUtilDate("John Doe 2", "124 Sesame Street", "123-456-789", new Date(), new Date());
ContactWithJavaUtilDate contact3 = new ContactWithJavaUtilDate("John Doe 3", "125 Sesame Street", "123-456-789", new Date(), new Date());
contacts.add(contact1);
contacts.add(contact2);
contacts.add(contact3);
return contacts;
}
@GetMapping("/plain")
public List<PlainContact> getPlainContacts() {
List<PlainContact> contacts = new ArrayList<>();
PlainContact contact1 = new PlainContact("John Doe", "123 Sesame Street", "123-456-789", LocalDate.now(), LocalDateTime.now());
PlainContact contact2 = new PlainContact("John Doe 2", "124 Sesame Street", "123-456-789", LocalDate.now(), LocalDateTime.now());
PlainContact contact3 = new PlainContact("John Doe 3", "125 Sesame Street", "123-456-789", LocalDate.now(), LocalDateTime.now());
contacts.add(contact1);
contacts.add(contact2);
contacts.add(contact3);
return contacts;
}
@GetMapping("/plainWithJavaUtilDate")
public List<PlainContactWithJavaUtilDate> getPlainContactsWithJavaUtilDate() {
List<PlainContactWithJavaUtilDate> contacts = new ArrayList<>();
PlainContactWithJavaUtilDate contact1 = new PlainContactWithJavaUtilDate("John Doe", "123 Sesame Street", "123-456-789", new Date(), new Date());
PlainContactWithJavaUtilDate contact2 = new PlainContactWithJavaUtilDate("John Doe 2", "124 Sesame Street", "123-456-789", new Date(), new Date());
PlainContactWithJavaUtilDate contact3 = new PlainContactWithJavaUtilDate("John Doe 3", "125 Sesame Street", "123-456-789", new Date(), new Date());
contacts.add(contact1);
contacts.add(contact2);
contacts.add(contact3);
return contacts;
}
}
@@ -0,0 +1,69 @@
package com.baeldung.jsondateformat;
import com.fasterxml.jackson.annotation.JsonFormat;
import java.util.Date;
public class ContactWithJavaUtilDate {
private String name;
private String address;
private String phone;
@JsonFormat(pattern="yyyy-MM-dd")
private Date birthday;
@JsonFormat(pattern="yyyy-MM-dd HH:mm:ss")
private Date lastUpdate;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public Date getLastUpdate() {
return lastUpdate;
}
public void setLastUpdate(Date lastUpdate) {
this.lastUpdate = lastUpdate;
}
public ContactWithJavaUtilDate() {
}
public ContactWithJavaUtilDate(String name, String address, String phone, Date birthday, Date lastUpdate) {
this.name = name;
this.address = address;
this.phone = phone;
this.birthday = birthday;
this.lastUpdate = lastUpdate;
}
}
@@ -0,0 +1,66 @@
package com.baeldung.jsondateformat;
import java.time.LocalDate;
import java.time.LocalDateTime;
public class PlainContact {
private String name;
private String address;
private String phone;
private LocalDate birthday;
private LocalDateTime lastUpdate;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public LocalDate getBirthday() {
return birthday;
}
public void setBirthday(LocalDate birthday) {
this.birthday = birthday;
}
public LocalDateTime getLastUpdate() {
return lastUpdate;
}
public void setLastUpdate(LocalDateTime lastUpdate) {
this.lastUpdate = lastUpdate;
}
public PlainContact() {
}
public PlainContact(String name, String address, String phone, LocalDate birthday, LocalDateTime lastUpdate) {
this.name = name;
this.address = address;
this.phone = phone;
this.birthday = birthday;
this.lastUpdate = lastUpdate;
}
}
@@ -0,0 +1,69 @@
package com.baeldung.jsondateformat;
import com.fasterxml.jackson.annotation.JsonFormat;
import java.util.Date;
public class PlainContactWithJavaUtilDate {
private String name;
private String address;
private String phone;
@JsonFormat(pattern="yyyy-MM-dd")
private Date birthday;
@JsonFormat(pattern="yyyy-MM-dd HH:mm:ss")
private Date lastUpdate;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public Date getLastUpdate() {
return lastUpdate;
}
public void setLastUpdate(Date lastUpdate) {
this.lastUpdate = lastUpdate;
}
public PlainContactWithJavaUtilDate() {
}
public PlainContactWithJavaUtilDate(String name, String address, String phone, Date birthday, Date lastUpdate) {
this.name = name;
this.address = address;
this.phone = phone;
this.birthday = birthday;
this.lastUpdate = lastUpdate;
}
}
@@ -0,0 +1,11 @@
package com.baeldung.jsonexception;
public class CustomException extends RuntimeException {
private static final long serialVersionUID = 1L;
public CustomException() {
super("Custom exception message.");
}
}
@@ -0,0 +1,17 @@
package com.baeldung.jsonexception;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
@RestControllerAdvice
public class ErrorHandler {
@ExceptionHandler(CustomException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public CustomException handleCustomException(CustomException ce) {
return ce;
}
}
@@ -0,0 +1,14 @@
package com.baeldung.jsonexception;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class MainController {
@GetMapping("/")
public void index() throws CustomException {
throw new CustomException();
}
}
@@ -0,0 +1,12 @@
package com.baeldung.propertyeditor;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class PropertyEditorApplication {
public static void main(String[] args) {
SpringApplication.run(PropertyEditorApplication.class, args);
}
}
@@ -0,0 +1,36 @@
package com.baeldung.propertyeditor;
import org.springframework.http.MediaType;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.baeldung.propertyeditor.creditcard.CreditCard;
import com.baeldung.propertyeditor.exotictype.editor.CustomExoticTypeEditor;
import com.baeldung.propertyeditor.exotictype.model.ExoticType;
@RestController
@RequestMapping(value = "/property-editor")
public class PropertyEditorRestController {
@GetMapping(value = "/credit-card/{card-no}",
produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public CreditCard parseCreditCardNumber(@PathVariable("card-no") CreditCard creditCard) {
return creditCard;
}
@GetMapping(value = "/exotic-type/{value}",
produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public ExoticType parseExoticType(@PathVariable("value") ExoticType exoticType) {
return exoticType;
}
@InitBinder
public void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(ExoticType.class, new CustomExoticTypeEditor());
}
}
@@ -0,0 +1,41 @@
package com.baeldung.propertyeditor.creditcard;
public class CreditCard {
private String rawCardNumber;
private Integer bankIdNo;
private Integer accountNo;
private Integer checkCode;
public String getRawCardNumber() {
return rawCardNumber;
}
public void setRawCardNumber(String rawCardNumber) {
this.rawCardNumber = rawCardNumber;
}
public Integer getBankIdNo() {
return bankIdNo;
}
public void setBankIdNo(Integer bankIdNo) {
this.bankIdNo = bankIdNo;
}
public Integer getAccountNo() {
return accountNo;
}
public void setAccountNo(Integer accountNo) {
this.accountNo = accountNo;
}
public Integer getCheckCode() {
return checkCode;
}
public void setCheckCode(Integer checkCode) {
this.checkCode = checkCode;
}
}
@@ -0,0 +1,39 @@
package com.baeldung.propertyeditor.creditcard;
import java.beans.PropertyEditorSupport;
import org.springframework.util.StringUtils;
public class CreditCardEditor extends PropertyEditorSupport {
@Override
public String getAsText() {
CreditCard creditCard = (CreditCard) getValue();
return creditCard == null ? "" : creditCard.getRawCardNumber();
}
@Override
public void setAsText(String text) throws IllegalArgumentException {
if (StringUtils.isEmpty(text)) {
setValue(null);
} else {
CreditCard creditCard = new CreditCard();
creditCard.setRawCardNumber(text);
String cardNo = text.replaceAll("-", "");
if (cardNo.length() != 16)
throw new IllegalArgumentException("Credit card format should be xxxx-xxxx-xxxx-xxxx");
try {
creditCard.setBankIdNo( Integer.valueOf(cardNo.substring(0, 6)) );
creditCard.setAccountNo( Integer.valueOf(cardNo.substring(6, cardNo.length() - 1)) );
creditCard.setCheckCode( Integer.valueOf(cardNo.substring(cardNo.length() - 1)) );
} catch (NumberFormatException nfe) {
throw new IllegalArgumentException(nfe);
}
setValue(creditCard);
}
}
}
@@ -0,0 +1,23 @@
package com.baeldung.propertyeditor.exotictype.editor;
import java.beans.PropertyEditorSupport;
import com.baeldung.propertyeditor.exotictype.model.ExoticType;
public class CustomExoticTypeEditor extends PropertyEditorSupport {
@Override
public String getAsText() {
ExoticType exoticType = (ExoticType) getValue();
return exoticType == null ? "" : exoticType.getName();
}
@Override
public void setAsText(String text) throws IllegalArgumentException {
ExoticType exoticType = new ExoticType();
exoticType.setName(text.toUpperCase());
setValue(exoticType);
}
}
@@ -0,0 +1,14 @@
package com.baeldung.propertyeditor.exotictype.model;
public class ExoticType {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
@@ -0,0 +1,25 @@
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
spring.jackson.time-zone=Europe/Zagreb
spring.h2.console.path=/h2
spring.h2.console.enabled=true
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
spring.main.allow-bean-definition-overriding=true
javers.mappingStyle=FIELD
javers.algorithm=SIMPLE
javers.commitIdGenerator=synchronized_sequence
javers.prettyPrint=true
javers.typeSafeValues=false
javers.newObjectSnapshot=true
javers.packagesToScan=
javers.auditableAspectEnabled=true
javers.springDataAuditableRepositoryAspectEnabled=true
javers.sqlSchema=
javers.sqlSchemaManagementEnabled=true
javers.prettyPrintDateFormats.localDateTime=dd MMM yyyy, HH:mm:ss
javers.prettyPrintDateFormats.zonedDateTime=dd MMM yyyy, HH:mm:ssZ
javers.prettyPrintDateFormats.localDate=dd MMM yyyy
javers.prettyPrintDateFormats.localTime=HH:mm:ss
@@ -0,0 +1,26 @@
package com.baeldung.disableautoconfig;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ApplicationContext;
import org.springframework.test.context.junit4.SpringRunner;
import javax.sql.DataSource;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = SpringDataJPA.class)
public class SpringDataJPAIntegrationTest {
@Autowired
private ApplicationContext context;
@Test(expected = NoSuchBeanDefinitionException.class)
public void givenAutoConfigDisabled_whenStarting_thenNoAutoconfiguredBeansInContext() {
context.getBean(DataSource.class);
}
}
@@ -0,0 +1,25 @@
package com.baeldung.disableautoconfig;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ApplicationContext;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = SpringDataMongoDB.class)
public class SpringDataMongoDBIntegrationTest {
@Autowired
private ApplicationContext context;
@Test(expected = NoSuchBeanDefinitionException.class)
public void givenAutoConfigDisabled_whenStarting_thenNoAutoconfiguredBeansInContext() {
context.getBean(MongoTemplate.class);
}
}
@@ -0,0 +1,25 @@
package com.baeldung.disableautoconfig;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ApplicationContext;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = SpringDataRedis.class)
public class SpringDataRedisIntegrationTest {
@Autowired
private ApplicationContext context;
@Test(expected = NoSuchBeanDefinitionException.class)
public void givenAutoConfigDisabled_whenStarting_thenNoAutoconfiguredBeansInContext() {
context.getBean(RedisTemplate.class);
}
}
@@ -0,0 +1,100 @@
package com.baeldung.jsondateformat;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.http.ResponseEntity;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit4.SpringRunner;
import java.io.IOException;
import java.text.ParseException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.List;
import java.util.Map;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT;
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = RANDOM_PORT, classes = ContactApp.class)
@TestPropertySource(properties = {
"spring.jackson.date-format=yyyy-MM-dd HH:mm:ss"
})
public class ContactAppIntegrationTest {
private final ObjectMapper mapper = new ObjectMapper();
@LocalServerPort
private int port;
@Autowired
private TestRestTemplate restTemplate;
@Test
public void givenJsonFormatAnnotationAndJava8DateType_whenGet_thenReturnExpectedDateFormat() throws IOException, ParseException {
ResponseEntity<String> response = restTemplate.getForEntity("http://localhost:" + port + "/contacts", String.class);
assertEquals(200, response.getStatusCodeValue());
List<Map<String, String>> respMap = mapper.readValue(response.getBody(), new TypeReference<List<Map<String, String>>>(){});
LocalDate birthdayDate = LocalDate.parse(respMap.get(0).get("birthday"), DateTimeFormatter.ofPattern("yyyy-MM-dd"));
LocalDateTime lastUpdateTime = LocalDateTime.parse(respMap.get(0).get("lastUpdate"), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
assertNotNull(birthdayDate);
assertNotNull(lastUpdateTime);
}
@Test
public void givenJsonFormatAnnotationAndLegacyDateType_whenGet_thenReturnExpectedDateFormat() throws IOException {
ResponseEntity<String> response = restTemplate.getForEntity("http://localhost:" + port + "/contacts/javaUtilDate", String.class);
assertEquals(200, response.getStatusCodeValue());
List<Map<String, String>> respMap = mapper.readValue(response.getBody(), new TypeReference<List<Map<String, String>>>(){});
LocalDate birthdayDate = LocalDate.parse(respMap.get(0).get("birthday"), DateTimeFormatter.ofPattern("yyyy-MM-dd"));
LocalDateTime lastUpdateTime = LocalDateTime.parse(respMap.get(0).get("lastUpdate"), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
assertNotNull(birthdayDate);
assertNotNull(lastUpdateTime);
}
@Test
public void givenDefaultDateFormatInAppPropertiesAndLegacyDateType_whenGet_thenReturnExpectedDateFormat() throws IOException {
ResponseEntity<String> response = restTemplate.getForEntity("http://localhost:" + port + "/contacts/plainWithJavaUtilDate", String.class);
assertEquals(200, response.getStatusCodeValue());
List<Map<String, String>> respMap = mapper.readValue(response.getBody(), new TypeReference<List<Map<String, String>>>(){});
LocalDate birthdayDate = LocalDate.parse(respMap.get(0).get("birthday"), DateTimeFormatter.ofPattern("yyyy-MM-dd"));
LocalDateTime lastUpdateTime = LocalDateTime.parse(respMap.get(0).get("lastUpdate"), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
assertNotNull(birthdayDate);
assertNotNull(lastUpdateTime);
}
@Test(expected = DateTimeParseException.class)
public void givenDefaultDateFormatInAppPropertiesAndJava8DateType_whenGet_thenNotApplyFormat() throws IOException {
ResponseEntity<String> response = restTemplate.getForEntity("http://localhost:" + port + "/contacts/plain", String.class);
assertEquals(200, response.getStatusCodeValue());
List<Map<String, String>> respMap = mapper.readValue(response.getBody(), new TypeReference<List<Map<String, String>>>(){});
LocalDate birthdayDate = LocalDate.parse(respMap.get(0).get("birthday"), DateTimeFormatter.ofPattern("yyyy-MM-dd"));
LocalDateTime lastUpdateTime = LocalDateTime.parse(respMap.get(0).get("lastUpdate"), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
}
}
@@ -0,0 +1,67 @@
package com.baeldung.jsondateformat;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.http.ResponseEntity;
import org.springframework.test.context.junit4.SpringRunner;
import java.io.IOException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Map;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT;
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = RANDOM_PORT, classes = ContactApp.class)
public class ContactAppWithObjectMapperCustomizerIntegrationTest {
private final ObjectMapper mapper = new ObjectMapper();
@Autowired
private TestRestTemplate restTemplate;
@LocalServerPort
private int port;
@Test
public void givenDefaultDateFormatInAppPropertiesAndLegacyDateType_whenGet_thenReturnExpectedDateFormat() throws IOException {
ResponseEntity<String> response = restTemplate.getForEntity("http://localhost:" + this.port + "/contacts/plainWithJavaUtilDate", String.class);
assertEquals(200, response.getStatusCodeValue());
List<Map<String, String>> respMap = mapper.readValue(response.getBody(), new TypeReference<List<Map<String, String>>>(){});
LocalDate birthdayDate = LocalDate.parse(respMap.get(0).get("birthday"), DateTimeFormatter.ofPattern("yyyy-MM-dd"));
LocalDateTime lastUpdateTime = LocalDateTime.parse(respMap.get(0).get("lastUpdate"), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
assertNotNull(birthdayDate);
assertNotNull(lastUpdateTime);
}
@Test
public void givenDefaultDateFormatInAppPropertiesAndJava8DateType_whenGet_thenReturnExpectedDateFormat() throws IOException {
ResponseEntity<String> response = restTemplate.getForEntity("http://localhost:" + this.port + "/contacts/plain", String.class);
assertEquals(200, response.getStatusCodeValue());
List<Map<String, String>> respMap = mapper.readValue(response.getBody(), new TypeReference<List<Map<String, String>>>(){});
LocalDate birthdayDate = LocalDate.parse(respMap.get(0).get("birthday"), DateTimeFormatter.ofPattern("yyyy-MM-dd"));
LocalDateTime lastUpdateTime = LocalDateTime.parse(respMap.get(0).get("lastUpdate"), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
assertNotNull(birthdayDate);
assertNotNull(lastUpdateTime);
}
}
@@ -0,0 +1,19 @@
package com.baeldung.jsonexception;
import org.junit.Test;
import com.baeldung.jsonexception.CustomException;
import com.baeldung.jsonexception.MainController;
public class MainControllerIntegrationTest {
@Test(expected = CustomException.class)
public void givenIndex_thenCustomException() throws CustomException {
MainController mainController = new MainController();
mainController.index();
}
}
@@ -0,0 +1,41 @@
package com.baeldung.propertyeditor.creditcard;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
public class CreditCardEditorUnitTest {
private CreditCardEditor creditCardEditor;
@Before
public void setup() {
creditCardEditor = new CreditCardEditor();
}
@Test(expected=IllegalArgumentException.class)
public void whenInvalidCardNoWithLessDigits_thenThrowsException() {
creditCardEditor.setAsText("123-123-123-123");
}
@Test(expected=IllegalArgumentException.class)
public void whenInvalidCardNoWithNonDigits_thenThrowsException() {
creditCardEditor.setAsText("1234-1234-xxxx-yyyy");
}
@Test
public void whenCardNoWithNonDigits_parseCreditCard() {
creditCardEditor.setAsText("1234-5678-9123-4560");
CreditCard creditCard = (CreditCard) creditCardEditor.getValue();
Assert.assertNotNull(creditCard);
Assert.assertEquals(123456, creditCard.getBankIdNo().intValue());
Assert.assertEquals(789123456, creditCard.getAccountNo().intValue());
Assert.assertEquals(0, creditCard.getCheckCode().intValue());
}
}
@@ -0,0 +1,24 @@
target/
!.mvn/wrapper/maven-wrapper.jar
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
### NetBeans ###
nbproject/private/
build/
nbbuild/
dist/
nbdist/
.nb-gradle/
@@ -0,0 +1 @@
distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.5.2/apache-maven-3.5.2-bin.zip
@@ -0,0 +1,6 @@
## Spring Boot Keycloak
This module contains articles about Keycloak in Spring Boot projects.
## Relevant articles:
- [A Quick Guide to Using Keycloak with Spring Boot](https://www.baeldung.com/spring-boot-keycloak)
+225
View File
@@ -0,0 +1,225 @@
#!/bin/sh
# ----------------------------------------------------------------------------
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
# ----------------------------------------------------------------------------
# ----------------------------------------------------------------------------
# Maven2 Start Up Batch script
#
# Required ENV vars:
# ------------------
# JAVA_HOME - location of a JDK home dir
#
# Optional ENV vars
# -----------------
# M2_HOME - location of maven2's installed home dir
# MAVEN_OPTS - parameters passed to the Java VM when running Maven
# e.g. to debug Maven itself, use
# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
# MAVEN_SKIP_RC - flag to disable loading of mavenrc files
# ----------------------------------------------------------------------------
if [ -z "$MAVEN_SKIP_RC" ] ; then
if [ -f /etc/mavenrc ] ; then
. /etc/mavenrc
fi
if [ -f "$HOME/.mavenrc" ] ; then
. "$HOME/.mavenrc"
fi
fi
# OS specific support. $var _must_ be set to either true or false.
cygwin=false;
darwin=false;
mingw=false
case "`uname`" in
CYGWIN*) cygwin=true ;;
MINGW*) mingw=true;;
Darwin*) darwin=true
# Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
# See https://developer.apple.com/library/mac/qa/qa1170/_index.html
if [ -z "$JAVA_HOME" ]; then
if [ -x "/usr/libexec/java_home" ]; then
export JAVA_HOME="`/usr/libexec/java_home`"
else
export JAVA_HOME="/Library/Java/Home"
fi
fi
;;
esac
if [ -z "$JAVA_HOME" ] ; then
if [ -r /etc/gentoo-release ] ; then
JAVA_HOME=`java-config --jre-home`
fi
fi
if [ -z "$M2_HOME" ] ; then
## resolve links - $0 may be a link to maven's home
PRG="$0"
# need this for relative symlinks
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG="`dirname "$PRG"`/$link"
fi
done
saveddir=`pwd`
M2_HOME=`dirname "$PRG"`/..
# make it fully qualified
M2_HOME=`cd "$M2_HOME" && pwd`
cd "$saveddir"
# echo Using m2 at $M2_HOME
fi
# For Cygwin, ensure paths are in UNIX format before anything is touched
if $cygwin ; then
[ -n "$M2_HOME" ] &&
M2_HOME=`cygpath --unix "$M2_HOME"`
[ -n "$JAVA_HOME" ] &&
JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
[ -n "$CLASSPATH" ] &&
CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
fi
# For Migwn, ensure paths are in UNIX format before anything is touched
if $mingw ; then
[ -n "$M2_HOME" ] &&
M2_HOME="`(cd "$M2_HOME"; pwd)`"
[ -n "$JAVA_HOME" ] &&
JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
# TODO classpath?
fi
if [ -z "$JAVA_HOME" ]; then
javaExecutable="`which javac`"
if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
# readlink(1) is not available as standard on Solaris 10.
readLink=`which readlink`
if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
if $darwin ; then
javaHome="`dirname \"$javaExecutable\"`"
javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
else
javaExecutable="`readlink -f \"$javaExecutable\"`"
fi
javaHome="`dirname \"$javaExecutable\"`"
javaHome=`expr "$javaHome" : '\(.*\)/bin'`
JAVA_HOME="$javaHome"
export JAVA_HOME
fi
fi
fi
if [ -z "$JAVACMD" ] ; then
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
else
JAVACMD="`which java`"
fi
fi
if [ ! -x "$JAVACMD" ] ; then
echo "Error: JAVA_HOME is not defined correctly." >&2
echo " We cannot execute $JAVACMD" >&2
exit 1
fi
if [ -z "$JAVA_HOME" ] ; then
echo "Warning: JAVA_HOME environment variable is not set."
fi
CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
# traverses directory structure from process work directory to filesystem root
# first directory with .mvn subdirectory is considered project base directory
find_maven_basedir() {
if [ -z "$1" ]
then
echo "Path not specified to find_maven_basedir"
return 1
fi
basedir="$1"
wdir="$1"
while [ "$wdir" != '/' ] ; do
if [ -d "$wdir"/.mvn ] ; then
basedir=$wdir
break
fi
# workaround for JBEAP-8937 (on Solaris 10/Sparc)
if [ -d "${wdir}" ]; then
wdir=`cd "$wdir/.."; pwd`
fi
# end of workaround
done
echo "${basedir}"
}
# concatenates all lines of a file
concat_lines() {
if [ -f "$1" ]; then
echo "$(tr -s '\n' ' ' < "$1")"
fi
}
BASE_DIR=`find_maven_basedir "$(pwd)"`
if [ -z "$BASE_DIR" ]; then
exit 1;
fi
export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
echo $MAVEN_PROJECTBASEDIR
MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
# For Cygwin, switch paths to Windows format before running java
if $cygwin; then
[ -n "$M2_HOME" ] &&
M2_HOME=`cygpath --path --windows "$M2_HOME"`
[ -n "$JAVA_HOME" ] &&
JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
[ -n "$CLASSPATH" ] &&
CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
[ -n "$MAVEN_PROJECTBASEDIR" ] &&
MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
fi
WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
exec "$JAVACMD" \
$MAVEN_OPTS \
-classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
"-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
+143
View File
@@ -0,0 +1,143 @@
@REM ----------------------------------------------------------------------------
@REM Licensed to the Apache Software Foundation (ASF) under one
@REM or more contributor license agreements. See the NOTICE file
@REM distributed with this work for additional information
@REM regarding copyright ownership. The ASF licenses this file
@REM to you under the Apache License, Version 2.0 (the
@REM "License"); you may not use this file except in compliance
@REM with the License. You may obtain a copy of the License at
@REM
@REM http://www.apache.org/licenses/LICENSE-2.0
@REM
@REM Unless required by applicable law or agreed to in writing,
@REM software distributed under the License is distributed on an
@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@REM KIND, either express or implied. See the License for the
@REM specific language governing permissions and limitations
@REM under the License.
@REM ----------------------------------------------------------------------------
@REM ----------------------------------------------------------------------------
@REM Maven2 Start Up Batch script
@REM
@REM Required ENV vars:
@REM JAVA_HOME - location of a JDK home dir
@REM
@REM Optional ENV vars
@REM M2_HOME - location of maven2's installed home dir
@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending
@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
@REM e.g. to debug Maven itself, use
@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
@REM ----------------------------------------------------------------------------
@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
@echo off
@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on'
@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
@REM set %HOME% to equivalent of $HOME
if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
@REM Execute a user defined script before this one
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
@REM check for pre script, once with legacy .bat ending and once with .cmd ending
if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
:skipRcPre
@setlocal
set ERROR_CODE=0
@REM To isolate internal variables from possible post scripts, we use another setlocal
@setlocal
@REM ==== START VALIDATION ====
if not "%JAVA_HOME%" == "" goto OkJHome
echo.
echo Error: JAVA_HOME not found in your environment. >&2
echo Please set the JAVA_HOME variable in your environment to match the >&2
echo location of your Java installation. >&2
echo.
goto error
:OkJHome
if exist "%JAVA_HOME%\bin\java.exe" goto init
echo.
echo Error: JAVA_HOME is set to an invalid directory. >&2
echo JAVA_HOME = "%JAVA_HOME%" >&2
echo Please set the JAVA_HOME variable in your environment to match the >&2
echo location of your Java installation. >&2
echo.
goto error
@REM ==== END VALIDATION ====
:init
@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
@REM Fallback to current working directory if not found.
set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
set EXEC_DIR=%CD%
set WDIR=%EXEC_DIR%
:findBaseDir
IF EXIST "%WDIR%"\.mvn goto baseDirFound
cd ..
IF "%WDIR%"=="%CD%" goto baseDirNotFound
set WDIR=%CD%
goto findBaseDir
:baseDirFound
set MAVEN_PROJECTBASEDIR=%WDIR%
cd "%EXEC_DIR%"
goto endDetectBaseDir
:baseDirNotFound
set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
cd "%EXEC_DIR%"
:endDetectBaseDir
IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
@setlocal EnableExtensions EnableDelayedExpansion
for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
:endReadAdditionalConfig
SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
if ERRORLEVEL 1 goto error
goto end
:error
set ERROR_CODE=1
:end
@endlocal & set ERROR_CODE=%ERROR_CODE%
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
@REM check for post script, once with legacy .bat ending and once with .cmd ending
if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
:skipRcPost
@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
if "%MAVEN_BATCH_PAUSE%" == "on" pause
if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
exit /B %ERROR_CODE%
@@ -0,0 +1,82 @@
<?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>com.baeldung.keycloak</groupId>
<artifactId>spring-boot-keycloak</artifactId>
<version>0.0.1</version>
<name>spring-boot-keycloak</name>
<packaging>jar</packaging>
<description>This is a simple application demonstrating integration between Keycloak and Spring Boot.</description>
<parent>
<groupId>com.baeldung</groupId>
<artifactId>parent-boot-1</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../../parent-boot-1</relativePath>
</parent>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.keycloak.bom</groupId>
<artifactId>keycloak-adapter-bom</artifactId>
<version>${keycloak-adapter-bom.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-spring-boot-starter</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-test</artifactId>
<scope>test</scope>
</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>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<properties>
<keycloak-adapter-bom.version>3.3.0.Final</keycloak-adapter-bom.version>
</properties>
</project>
@@ -0,0 +1,49 @@
package com.baeldung.keycloak;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@Entity
public class Customer {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private String name;
private String serviceRendered;
private String address;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getServiceRendered() {
return serviceRendered;
}
public void setServiceRendered(String serviceRendered) {
this.serviceRendered = serviceRendered;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
@@ -0,0 +1,7 @@
package com.baeldung.keycloak;
import org.springframework.data.repository.CrudRepository;
public interface CustomerDAO extends CrudRepository<Customer, Long> {
}
@@ -0,0 +1,52 @@
package com.baeldung.keycloak;
import org.keycloak.adapters.springboot.KeycloakSpringBootConfigResolver;
import org.keycloak.adapters.springsecurity.KeycloakSecurityComponents;
import org.keycloak.adapters.springsecurity.authentication.KeycloakAuthenticationProvider;
import org.keycloak.adapters.springsecurity.config.KeycloakWebSecurityConfigurerAdapter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.authority.mapping.SimpleAuthorityMapper;
import org.springframework.security.core.session.SessionRegistryImpl;
import org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy;
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
@Configuration
@EnableWebSecurity
@ComponentScan(basePackageClasses = KeycloakSecurityComponents.class)
class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter {
// Submits the KeycloakAuthenticationProvider to the AuthenticationManager
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
KeycloakAuthenticationProvider keycloakAuthenticationProvider = keycloakAuthenticationProvider();
keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());
auth.authenticationProvider(keycloakAuthenticationProvider);
}
@Bean
public KeycloakSpringBootConfigResolver KeycloakConfigResolver() {
return new KeycloakSpringBootConfigResolver();
}
// Specifies the session authentication strategy
@Bean
@Override
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http.authorizeRequests()
.antMatchers("/customers*")
.hasRole("user")
.anyRequest()
.permitAll();
}
}
@@ -0,0 +1,14 @@
package com.baeldung.keycloak;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringBoot {
public static void main(String[] args) {
SpringApplication.run(SpringBoot.class, args);
}
}
@@ -0,0 +1,52 @@
package com.baeldung.keycloak;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import java.security.Principal;
import org.springframework.beans.factory.annotation.Autowired;
@Controller
public class WebController {
@Autowired
private CustomerDAO customerDAO;
@GetMapping(path = "/")
public String index() {
return "external";
}
@GetMapping(path = "/customers")
public String customers(Principal principal, Model model) {
addCustomers();
Iterable<Customer> customers = customerDAO.findAll();
model.addAttribute("customers", customers);
model.addAttribute("username", principal.getName());
return "customers";
}
// add customers for demonstration
public void addCustomers() {
Customer customer1 = new Customer();
customer1.setAddress("1111 foo blvd");
customer1.setName("Foo Industries");
customer1.setServiceRendered("Important services");
customerDAO.save(customer1);
Customer customer2 = new Customer();
customer2.setAddress("2222 bar street");
customer2.setName("Bar LLP");
customer2.setServiceRendered("Important services");
customerDAO.save(customer2);
Customer customer3 = new Customer();
customer3.setAddress("33 main street");
customer3.setName("Big LLC");
customer3.setServiceRendered("Important services");
customerDAO.save(customer3);
}
}
@@ -0,0 +1,9 @@
### server port
server.port=8081
#Keycloak Configuration
keycloak.auth-server-url=http://localhost:8180/auth
keycloak.realm=SpringBootKeycloak
keycloak.resource=login-app
keycloak.public-client=true
keycloak.principal-attribute=preferred_username
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="STDOUT" />
</root>
</configuration>
@@ -0,0 +1,33 @@
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head th:include="layout :: headerFragment">
</head>
<body>
<div id="container">
<h1>
Hello, <span th:text="${username}">--name--</span>.
</h1>
<table class="table table-striped">
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Address</th>
<th>Service Rendered</th>
</tr>
</thead>
<tbody>
<tr th:each="customer : ${customers}">
<td th:text="${customer.id}">Text ...</td>
<td th:text="${customer.name}">Text ...</td>
<td th:text="${customer.address}">Text ...</td>
<td th:text="${customer.serviceRendered}">Text...</td>
</tr>
</tbody>
</table>
<div id="pagefoot" th:include="layout :: footerFragment">Footer
</div>
</div>
<!-- container -->
</body>
</html>
@@ -0,0 +1,31 @@
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head th:include="layout :: headerFragment">
</head>
<body>
<div class="container">
<div class="jumbotron text-center">
<h1>Customer Portal</h1>
</div>
<div>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam
erat lectus, vehicula feugiat ultricies at, tempus sed ante. Cras
arcu erat, lobortis vitae quam et, mollis pharetra odio. Nullam sit
amet congue ipsum. Nunc dapibus odio ut ligula venenatis porta non
id dui. Duis nec tempor tellus. Suspendisse id blandit ligula, sit
amet varius mauris. Nulla eu eros pharetra, tristique dui quis,
vehicula libero. Aenean a neque sit amet tellus porttitor rutrum nec
at leo.</p>
<h2>Existing Customers</h2>
<div class="well">
<b>Enter the intranet: </b><a th:href="@{/customers}">customers</a>
</div>
</div>
<div id="pagefoot" th:include="layout :: footerFragment">Footer
</div>
</div>
<!-- container -->
</body>
</html>
@@ -0,0 +1,18 @@
<head th:fragment="headerFragment">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Customer Portal</title>
<link
href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"
rel="stylesheet"
integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u"
crossorigin="anonymous"></link>
<link
href="https://cdn.datatables.net/1.10.16/css/jquery.dataTables.min.css"
rel="stylesheet"></link>
</head>
<div id="pagefoot" th:fragment="footerFragment">
<p>Document last modified 2017/10/23.</p>
<p>Copyright: Lorem Ipsum</p>
</div>
@@ -0,0 +1,50 @@
package com.baeldung.keycloak;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.keycloak.KeycloakPrincipal;
import org.keycloak.KeycloakSecurityContext;
import org.keycloak.adapters.springboot.client.KeycloakSecurityContextClientRequestInterceptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.Spy;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import static org.junit.Assert.assertNotNull;
import static org.mockito.Mockito.when;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = SpringBoot.class)
public class KeycloakConfigurationIntegrationTest {
@Spy
private KeycloakSecurityContextClientRequestInterceptor factory;
private MockHttpServletRequest servletRequest;
@Mock
public KeycloakSecurityContext keycloakSecurityContext;
@Mock
private KeycloakPrincipal keycloakPrincipal;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
servletRequest = new MockHttpServletRequest();
RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(servletRequest));
servletRequest.setUserPrincipal(keycloakPrincipal);
when(keycloakPrincipal.getKeycloakSecurityContext()).thenReturn(keycloakSecurityContext);
}
@Test
public void testGetKeycloakSecurityContext() throws Exception {
assertNotNull(keycloakPrincipal.getKeycloakSecurityContext());
}
}
@@ -0,0 +1,17 @@
package org.baeldung;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import com.baeldung.keycloak.SpringBoot;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = SpringBoot.class)
public class SpringContextTest {
@Test
public void whenSpringContextIsBootstrapped_thenNoExceptions() {
}
}
@@ -0,0 +1,14 @@
## Spring Boot Properties
This module contains articles about Properties in Spring Boot.
### Relevant Articles:
- [Reloading Properties Files in Spring](https://www.baeldung.com/spring-reloading-properties)
- [Guide to @ConfigurationProperties in Spring Boot](https://www.baeldung.com/configuration-properties-in-spring-boot)
- [Load Spring Boot Properties From a JSON File](https://www.baeldung.com/spring-boot-json-properties)
- [Guide to @EnableConfigurationProperties](https://www.baeldung.com/spring-enable-config-properties)
- [Properties with Spring and Spring Boot](https://www.baeldung.com/properties-with-spring) - checkout the `com.baeldung.properties` package for all scenarios of properties injection and usage
- [A Quick Guide to Spring @Value](https://www.baeldung.com/spring-value-annotation)
- [Spring YAML Configuration](https://www.baeldung.com/spring-yaml)
- [Using Spring @Value with Defaults](https://www.baeldung.com/spring-value-defaults)
- [How to Inject a Property Value Into a Class Not Managed by Spring?](https://www.baeldung.com/inject-properties-value-non-spring-class)
@@ -0,0 +1 @@
application.theme.color=blue
@@ -0,0 +1 @@
application.theme.background=red
@@ -0,0 +1,111 @@
<?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>
<artifactId>spring-boot-properties</artifactId>
<name>spring-boot-properties</name>
<packaging>jar</packaging>
<description>Spring Boot Properties Module</description>
<parent>
<groupId>com.baeldung</groupId>
<artifactId>parent-boot-2</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../../parent-boot-2</relativePath>
</parent>
<dependencies>
<dependency>
<groupId>commons-configuration</groupId>
<artifactId>commons-configuration</artifactId>
<version>${commons-configuration.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter</artifactId>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>${guava.version}</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcore</artifactId>
<version>${httpcore.version}</version>
</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>
<finalName>spring-boot-properties</finalName>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
</build>
<profiles>
<profile>
<id>integration</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<executions>
<execution>
<phase>integration-test</phase>
<goals>
<goal>test</goal>
</goals>
<configuration>
<excludes>
<exclude>**/*LiveTest.java</exclude>
<exclude>**/*IntegrationTest.java</exclude>
<exclude>**/*IntTest.java</exclude>
</excludes>
</configuration>
</execution>
</executions>
<configuration>
<systemPropertyVariables>
<test.mime>json</test.mime>
</systemPropertyVariables>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.SR1</spring-cloud.version>
<commons-configuration.version>1.10</commons-configuration.version>
<guava.version>20.0</guava.version>
<httpcore.version>4.4.11</httpcore.version>
</properties>
</project>
@@ -0,0 +1,124 @@
package com.baeldung.configurationproperties;
import java.util.List;
import java.util.Map;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Pattern;
import org.hibernate.validator.constraints.Length;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.validation.annotation.Validated;
@Configuration
@PropertySource("classpath:configprops.properties")
@ConfigurationProperties(prefix = "mail")
@Validated
public class ConfigProperties {
@Validated
public static class Credentials {
@Length(max = 4, min = 1)
private String authMethod;
private String username;
private String password;
public String getAuthMethod() {
return authMethod;
}
public void setAuthMethod(String authMethod) {
this.authMethod = authMethod;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
@NotBlank
private String hostName;
@Min(1025)
@Max(65536)
private int port;
@Pattern(regexp = "^[a-z0-9._%+-]+@[a-z0-9.-]+\\.[a-z]{2,6}$")
private String from;
private Credentials credentials;
private List<String> defaultRecipients;
private Map<String, String> additionalHeaders;
public String getHostName() {
return hostName;
}
public void setHostName(String hostName) {
this.hostName = hostName;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
public String getFrom() {
return from;
}
public void setFrom(String from) {
this.from = from;
}
public Credentials getCredentials() {
return credentials;
}
public void setCredentials(Credentials credentials) {
this.credentials = credentials;
}
public List<String> getDefaultRecipients() {
return defaultRecipients;
}
public void setDefaultRecipients(List<String> defaultRecipients) {
this.defaultRecipients = defaultRecipients;
}
public Map<String, String> getAdditionalHeaders() {
return additionalHeaders;
}
public void setAdditionalHeaders(Map<String, String> additionalHeaders) {
this.additionalHeaders = additionalHeaders;
}
@Bean
@ConfigurationProperties(prefix = "item")
public Item item(){
return new Item();
}
}
@@ -0,0 +1,30 @@
package com.baeldung.configurationproperties;
public class Employee {
private String name;
private double salary;
public Employee(String name, double salary) {
super();
this.name = name;
this.salary = salary;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
}
@@ -0,0 +1,16 @@
package com.baeldung.configurationproperties;
import org.springframework.boot.context.properties.ConfigurationPropertiesBinding;
import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;
@Component
@ConfigurationPropertiesBinding
public class EmployeeConverter implements Converter<String, Employee> {
@Override
public Employee convert(String from) {
String[] data = from.split(",");
return new Employee(data[0], Double.parseDouble(data[1]));
}
}
@@ -0,0 +1,14 @@
package com.baeldung.configurationproperties;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.ConfigurationPropertiesScan;
@SpringBootApplication
@ConfigurationPropertiesScan
public class ImmutableConfigPropertiesApp {
public static void main(String[] args) {
SpringApplication.run(ImmutableConfigPropertiesApp.class, args);
}
}
@@ -0,0 +1,31 @@
package com.baeldung.configurationproperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.ConstructorBinding;
@ConfigurationProperties(prefix = "mail.credentials")
@ConstructorBinding
public class ImmutableCredentials {
private final String authMethod;
private final String username;
private final String password;
public ImmutableCredentials(String authMethod, String username, String password) {
this.authMethod = authMethod;
this.username = username;
this.password = password;
}
public String getAuthMethod() {
return authMethod;
}
public String getUsername() {
return username;
}
public String getPassword() {
return password;
}
}
@@ -0,0 +1,31 @@
package com.baeldung.configurationproperties;
public class Item {
private String name;
private int size;
public Item() {
}
public Item(String name, int size) {
this.name = name;
this.size = size;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
}
@@ -0,0 +1,14 @@
package com.baeldung.configurationproperties;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
@SpringBootApplication
@ComponentScan(basePackageClasses = { PropertyConversion.class, EmployeeConverter.class })
public class PropertiesConversionApplication {
public static void main(String[] args) {
SpringApplication.run(PropertiesConversionApplication.class, args);
}
}
@@ -0,0 +1,92 @@
package com.baeldung.configurationproperties;
import java.time.Duration;
import java.time.temporal.ChronoUnit;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.convert.DataSizeUnit;
import org.springframework.boot.convert.DurationUnit;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.util.unit.DataSize;
import org.springframework.util.unit.DataUnit;
@Configuration
@PropertySource("classpath:conversion.properties")
@ConfigurationProperties(prefix = "conversion")
public class PropertyConversion {
private Duration timeInDefaultUnit;
private Duration timeInNano;
@DurationUnit(ChronoUnit.DAYS)
private Duration timeInDays;
private DataSize sizeInDefaultUnit;
private DataSize sizeInGB;
@DataSizeUnit(DataUnit.TERABYTES)
private DataSize sizeInTB;
private Employee employee;
// Getters and setters
public Duration getTimeInDefaultUnit() {
return timeInDefaultUnit;
}
public void setTimeInDefaultUnit(Duration timeInDefaultUnit) {
this.timeInDefaultUnit = timeInDefaultUnit;
}
public Duration getTimeInNano() {
return timeInNano;
}
public void setTimeInNano(Duration timeInNano) {
this.timeInNano = timeInNano;
}
public Duration getTimeInDays() {
return timeInDays;
}
public void setTimeInDays(Duration timeInDays) {
this.timeInDays = timeInDays;
}
public DataSize getSizeInDefaultUnit() {
return sizeInDefaultUnit;
}
public void setSizeInDefaultUnit(DataSize sizeInDefaultUnit) {
this.sizeInDefaultUnit = sizeInDefaultUnit;
}
public DataSize getSizeInGB() {
return sizeInGB;
}
public void setSizeInGB(DataSize sizeInGB) {
this.sizeInGB = sizeInGB;
}
public DataSize getSizeInTB() {
return sizeInTB;
}
public void setSizeInTB(DataSize sizeInTB) {
this.sizeInTB = sizeInTB;
}
public Employee getEmployee() {
return employee;
}
public void setEmployee(Employee employee) {
this.employee = employee;
}
}
@@ -0,0 +1,14 @@
package com.baeldung.properties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableConfigurationProperties(AdditionalProperties.class)
public class AdditionalConfiguration {
@Autowired
private AdditionalProperties additionalProperties;
}
@@ -0,0 +1,28 @@
package com.baeldung.properties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@Configuration
@ConfigurationProperties(prefix = "additional")
public class AdditionalProperties {
private String unit;
private int max;
public String getUnit() {
return unit;
}
public void setUnit(String unit) {
this.unit = unit;
}
public int getMax() {
return max;
}
public void setMax(int max) {
this.max = max;
}
}
@@ -0,0 +1,17 @@
package com.baeldung.properties;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.annotation.ComponentScan;
import com.baeldung.configurationproperties.ConfigProperties;
@SpringBootApplication
@ComponentScan(basePackageClasses = { ConfigProperties.class, JsonProperties.class, CustomJsonProperties.class })
public class ConfigPropertiesDemoApplication {
public static void main(String[] args) {
new SpringApplicationBuilder(ConfigPropertiesDemoApplication.class).initializers(new JsonPropertyContextInitializer())
.run();
}
}
@@ -0,0 +1,71 @@
package com.baeldung.properties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Component
@ConfigurationProperties(prefix = "custom")
public class CustomJsonProperties {
private String host;
private int port;
private boolean resend;
private Person sender;
public static class Person {
private String name;
private String address;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
public String getHost() {
return host;
}
public void setHost(String host) {
this.host = host;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
public boolean isResend() {
return resend;
}
public void setResend(boolean resend) {
this.resend = resend;
}
public Person getSender() {
return sender;
}
public void setSender(Person sender) {
this.sender = sender;
}
}
@@ -0,0 +1,64 @@
package com.baeldung.properties;
import java.util.LinkedHashMap;
import java.util.List;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;
@Component
@PropertySource(value = "classpath:configprops.json", factory = JsonPropertySourceFactory.class)
@ConfigurationProperties
public class JsonProperties {
private String host;
private int port;
private boolean resend;
private List<String> topics;
private LinkedHashMap<String, ?> sender;
public LinkedHashMap<String, ?> getSender() {
return sender;
}
public void setSender(LinkedHashMap<String, ?> sender) {
this.sender = sender;
}
public List<String> getTopics() {
return topics;
}
public void setTopics(List<String> topics) {
this.topics = topics;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
public boolean isResend() {
return resend;
}
public void setResend(boolean resend) {
this.resend = resend;
}
public String getHost() {
return host;
}
public void setHost(String host) {
this.host = host;
}
}
@@ -0,0 +1,68 @@
package com.baeldung.properties;
import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.Resource;
import com.fasterxml.jackson.databind.ObjectMapper;
public class JsonPropertyContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
private final static String CUSTOM_PREFIX = "custom.";
@Override
@SuppressWarnings("unchecked")
public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
try {
Resource resource = configurableApplicationContext.getResource("classpath:configprops.json");
Map readValue = new ObjectMapper().readValue(resource.getInputStream(), Map.class);
Set<Map.Entry> set = readValue.entrySet();
List<MapPropertySource> propertySources = convertEntrySet(set, Optional.empty());
for (PropertySource propertySource : propertySources) {
configurableApplicationContext.getEnvironment()
.getPropertySources()
.addFirst(propertySource);
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private static List<MapPropertySource> convertEntrySet(Set<Map.Entry> entrySet, Optional<String> parentKey) {
return entrySet.stream()
.map((Map.Entry e) -> convertToPropertySourceList(e, parentKey))
.flatMap(Collection::stream)
.collect(Collectors.toList());
}
private static List<MapPropertySource> convertToPropertySourceList(Map.Entry e, Optional<String> parentKey) {
String key = parentKey.map(s -> s + ".")
.orElse("") + (String) e.getKey();
Object value = e.getValue();
return covertToPropertySourceList(key, value);
}
@SuppressWarnings("unchecked")
private static List<MapPropertySource> covertToPropertySourceList(String key, Object value) {
if (value instanceof LinkedHashMap) {
LinkedHashMap map = (LinkedHashMap) value;
Set<Map.Entry> entrySet = map.entrySet();
return convertEntrySet(entrySet, Optional.ofNullable(key));
}
String finalKey = CUSTOM_PREFIX + key;
return Collections.singletonList(new MapPropertySource(finalKey, Collections.singletonMap(finalKey, value)));
}
}
@@ -0,0 +1,21 @@
package com.baeldung.properties;
import java.io.IOException;
import java.util.Map;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.support.EncodedResource;
import org.springframework.core.io.support.PropertySourceFactory;
import com.fasterxml.jackson.databind.ObjectMapper;
public class JsonPropertySourceFactory implements PropertySourceFactory {
@Override
public PropertySource<?> createPropertySource(String name, EncodedResource resource) throws IOException {
Map readValue = new ObjectMapper().readValue(resource.getInputStream(), Map.class);
return new MapPropertySource("json-property", readValue);
}
}
@@ -0,0 +1,30 @@
package com.baeldung.properties.core;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.env.Environment;
public class ComponentInXmlUsingProperties implements InitializingBean {
@Autowired
private Environment env;
@Value("${key.something}")
private String injectedProperty;
public ComponentInXmlUsingProperties(final String propertyValue) {
super();
System.out.println("Constructor Injection - Property Value resolved to: " + propertyValue);
}
//
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("in afterPropertiesSet via @Value: " + injectedProperty);
System.out.println("in afterPropertiesSet Environment: " + env.getProperty("key.something"));
}
}
@@ -0,0 +1,30 @@
package com.baeldung.properties.core;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
@Component
public class ComponentUsingProperties implements InitializingBean {
@Autowired
private Environment env;
@Value("${key.something}")
private String injectedProperty;
public ComponentUsingProperties() {
super();
}
//
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("in afterPropertiesSet via @Value: " + injectedProperty);
System.out.println("in afterPropertiesSet Environment: " + env.getProperty("key.something"));
}
}
@@ -0,0 +1,25 @@
package com.baeldung.properties.external;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
@Configuration
@ComponentScan("org.baeldung.properties.core")
@PropertySource("classpath:foo.properties")
public class ExternalPropertiesWithJavaConfig {
public ExternalPropertiesWithJavaConfig() {
super();
}
// beans
@Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
}
@@ -0,0 +1,16 @@
package com.baeldung.properties.external;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
@Configuration
@ImportResource("classpath:configForProperties.xml")
@ComponentScan("org.baeldung.core")
public class ExternalPropertiesWithXmlConfig {
public ExternalPropertiesWithXmlConfig() {
super();
}
}
@@ -0,0 +1,16 @@
package com.baeldung.properties.external;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
@Configuration
@ImportResource("classpath:configForPropertiesOne.xml")
@ComponentScan("org.baeldung.core")
public class ExternalPropertiesWithXmlConfigOne {
public ExternalPropertiesWithXmlConfigOne() {
super();
}
}
@@ -0,0 +1,14 @@
package com.baeldung.properties.external;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
@Configuration
@ImportResource("classpath:basicConfigForPropertiesTwo.xml")
public class ExternalPropertiesWithXmlConfigTwo {
public ExternalPropertiesWithXmlConfigTwo() {
super();
}
}
@@ -0,0 +1,44 @@
package com.baeldung.properties.reloading;
import com.baeldung.properties.reloading.configs.ReloadableProperties;
import java.io.File;
import java.util.Properties;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.apache.commons.configuration.reloading.FileChangedReloadingStrategy;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
@SpringBootApplication
public class SpringBootPropertiesApplication {
@Bean
@ConditionalOnProperty(name = "spring.config.location", matchIfMissing = false)
public PropertiesConfiguration propertiesConfiguration(
@Value("${spring.config.location}") String path,
@Value("${spring.properties.refreshDelay}") long refreshDelay) throws Exception {
String filePath = path.substring("file:".length());
PropertiesConfiguration configuration = new PropertiesConfiguration(new File(filePath).getCanonicalPath());
FileChangedReloadingStrategy fileChangedReloadingStrategy = new FileChangedReloadingStrategy();
fileChangedReloadingStrategy.setRefreshDelay(refreshDelay);
configuration.setReloadingStrategy(fileChangedReloadingStrategy);
return configuration;
}
@Bean
@ConditionalOnBean(PropertiesConfiguration.class)
@Primary
public Properties properties(PropertiesConfiguration propertiesConfiguration) throws Exception {
ReloadableProperties properties = new ReloadableProperties(propertiesConfiguration);
return properties;
}
public static void main(String[] args) {
SpringApplication.run(SpringBootPropertiesApplication.class, args);
}
}
@@ -0,0 +1,10 @@
package com.baeldung.properties.reloading.configs;
public class PropertiesException extends RuntimeException {
public PropertiesException() {
}
public PropertiesException(Throwable cause) {
super(cause);
}
}
@@ -0,0 +1,49 @@
package com.baeldung.properties.reloading.configs;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.util.Properties;
import javax.naming.OperationNotSupportedException;
import org.apache.commons.configuration.PropertiesConfiguration;
public class ReloadableProperties extends Properties {
private PropertiesConfiguration propertiesConfiguration;
public ReloadableProperties(PropertiesConfiguration propertiesConfiguration) throws IOException {
super.load(new FileReader(propertiesConfiguration.getFile()));
this.propertiesConfiguration = propertiesConfiguration;
}
@Override
public synchronized Object setProperty(String key, String value) {
propertiesConfiguration.setProperty(key, value);
return super.setProperty(key, value);
}
@Override
public String getProperty(String key) {
String val = propertiesConfiguration.getString(key);
super.setProperty(key, val);
return val;
}
@Override
public String getProperty(String key, String defaultValue) {
String val = propertiesConfiguration.getString(key, defaultValue);
super.setProperty(key, val);
return val;
}
@Override
public synchronized void load(Reader reader) throws IOException {
throw new PropertiesException(new OperationNotSupportedException());
}
@Override
public synchronized void load(InputStream inStream) throws IOException {
throw new PropertiesException(new OperationNotSupportedException());
}
}
@@ -0,0 +1,33 @@
package com.baeldung.properties.reloading.configs;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.apache.commons.configuration.reloading.FileChangedReloadingStrategy;
import org.springframework.core.env.PropertySource;
import org.springframework.util.StringUtils;
public class ReloadablePropertySource extends PropertySource {
PropertiesConfiguration propertiesConfiguration;
public ReloadablePropertySource(String name, PropertiesConfiguration propertiesConfiguration) {
super(name);
this.propertiesConfiguration = propertiesConfiguration;
}
public ReloadablePropertySource(String name, String path) {
super(StringUtils.isEmpty(name) ? path : name);
try {
this.propertiesConfiguration = new PropertiesConfiguration(path);
FileChangedReloadingStrategy strategy = new FileChangedReloadingStrategy();
strategy.setRefreshDelay(1000);
this.propertiesConfiguration.setReloadingStrategy(strategy);
} catch (Exception e) {
throw new PropertiesException(e);
}
}
@Override
public Object getProperty(String s) {
return propertiesConfiguration.getProperty(s);
}
}

Some files were not shown because too many files have changed in this diff Show More