Merge branch 'master' into Mercator
This commit is contained in:
commit
2e4c950e4a
@ -0,0 +1,84 @@
|
||||
package com.baeldung.properties;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class MergePropertiesUnitTest {
|
||||
|
||||
@Test
|
||||
public void givenTwoProperties_whenMergedUsingIteration_thenAllPropertiesInResult() {
|
||||
Properties globalProperties = mergePropertiesByIteratingKeySet(propertiesA(), propertiesB());
|
||||
|
||||
testMergedProperties(globalProperties);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenTwoProperties_whenMergedUsingPutAll_thenAllPropertiesInResult() {
|
||||
Properties globalProperties = mergePropertiesByUsingPutAll(propertiesA(), propertiesB());
|
||||
|
||||
testMergedProperties(globalProperties);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenTwoProperties_whenMergedUsingStreamAPI_thenAllPropertiesInResult() {
|
||||
Properties globalProperties = mergePropertiesByUsingStreamApi(propertiesB(), propertiesA());
|
||||
|
||||
testMergedProperties(globalProperties);
|
||||
}
|
||||
|
||||
private Properties mergePropertiesByIteratingKeySet(Properties... properties) {
|
||||
Properties mergedProperties = new Properties();
|
||||
for (Properties property : properties) {
|
||||
Set<String> propertyNames = property.stringPropertyNames();
|
||||
for (String name : propertyNames) {
|
||||
String propertyValue = property.getProperty(name);
|
||||
mergedProperties.setProperty(name, propertyValue);
|
||||
}
|
||||
}
|
||||
return mergedProperties;
|
||||
}
|
||||
|
||||
private Properties mergePropertiesByUsingPutAll(Properties... properties) {
|
||||
Properties mergedProperties = new Properties();
|
||||
for (Properties property : properties) {
|
||||
mergedProperties.putAll(property);
|
||||
}
|
||||
return mergedProperties;
|
||||
}
|
||||
|
||||
private Properties mergePropertiesByUsingStreamApi(Properties... properties) {
|
||||
return Stream.of(properties)
|
||||
.collect(Properties::new, Map::putAll, Map::putAll);
|
||||
}
|
||||
|
||||
private Properties propertiesA() {
|
||||
Properties properties = new Properties();
|
||||
properties.setProperty("application.name", "my-app");
|
||||
properties.setProperty("application.version", "1.0");
|
||||
return properties;
|
||||
}
|
||||
|
||||
private Properties propertiesB() {
|
||||
Properties properties = new Properties();
|
||||
properties.setProperty("property-1", "sample property");
|
||||
properties.setProperty("property-2", "another sample property");
|
||||
return properties;
|
||||
}
|
||||
|
||||
private void testMergedProperties(Properties globalProperties) {
|
||||
assertThat("There should be 4 properties", globalProperties.size(), equalTo(4));
|
||||
assertEquals("Property should be", globalProperties.getProperty("application.name"), "my-app");
|
||||
assertEquals("Property should be", globalProperties.getProperty("application.version"), "1.0");
|
||||
assertEquals("Property should be", globalProperties.getProperty("property-1"), "sample property");
|
||||
assertEquals("Property should be", globalProperties.getProperty("property-2"), "another sample property");
|
||||
}
|
||||
|
||||
}
|
@ -61,6 +61,11 @@
|
||||
<version>3.3.0</version>
|
||||
<type>pom</type>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>uy.kohesive.injekt</groupId>
|
||||
<artifactId>injekt-core</artifactId>
|
||||
<version>1.16.1</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<properties>
|
||||
|
@ -1,10 +1,10 @@
|
||||
package com.baeldung.datamapping
|
||||
|
||||
data class User(
|
||||
val firstName: String,
|
||||
val lastName: String,
|
||||
val street: String,
|
||||
val houseNumber: String,
|
||||
val phone: String,
|
||||
val age: Int,
|
||||
val password: String)
|
||||
val firstName: String,
|
||||
val lastName: String,
|
||||
val street: String,
|
||||
val houseNumber: String,
|
||||
val phone: String,
|
||||
val age: Int,
|
||||
val password: String)
|
@ -3,10 +3,10 @@ package com.baeldung.datamapping
|
||||
import kotlin.reflect.full.memberProperties
|
||||
|
||||
fun User.toUserView() = UserView(
|
||||
name = "$firstName $lastName",
|
||||
address = "$street $houseNumber",
|
||||
telephone = phone,
|
||||
age = age
|
||||
name = "$firstName $lastName",
|
||||
address = "$street $houseNumber",
|
||||
telephone = phone,
|
||||
age = age
|
||||
)
|
||||
|
||||
fun User.toUserViewReflection() = with(::UserView) {
|
||||
|
@ -1,8 +1,8 @@
|
||||
package com.baeldung.datamapping
|
||||
|
||||
data class UserView(
|
||||
val name: String,
|
||||
val address: String,
|
||||
val telephone: String,
|
||||
val age: Int
|
||||
val name: String,
|
||||
val address: String,
|
||||
val telephone: String,
|
||||
val age: Int
|
||||
)
|
@ -0,0 +1,60 @@
|
||||
package com.baeldung.injekt
|
||||
|
||||
import org.slf4j.LoggerFactory
|
||||
import uy.kohesive.injekt.*
|
||||
import uy.kohesive.injekt.api.*
|
||||
import java.util.*
|
||||
|
||||
class DelegateInjectionApplication {
|
||||
companion object : InjektMain() {
|
||||
private val LOG = LoggerFactory.getLogger(DelegateInjectionApplication::class.java)
|
||||
@JvmStatic fun main(args: Array<String>) {
|
||||
DelegateInjectionApplication().run()
|
||||
}
|
||||
|
||||
override fun InjektRegistrar.registerInjectables() {
|
||||
addFactory {
|
||||
val value = FactoryInstance("Factory" + UUID.randomUUID().toString())
|
||||
LOG.info("Constructing instance: {}", value)
|
||||
value
|
||||
}
|
||||
|
||||
addSingletonFactory {
|
||||
val value = SingletonInstance("Singleton" + UUID.randomUUID().toString())
|
||||
LOG.info("Constructing singleton instance: {}", value)
|
||||
value
|
||||
}
|
||||
|
||||
addSingletonFactory { App() }
|
||||
}
|
||||
}
|
||||
|
||||
data class FactoryInstance(val value: String)
|
||||
data class SingletonInstance(val value: String)
|
||||
|
||||
class App {
|
||||
private val instance: FactoryInstance by injectValue()
|
||||
private val lazyInstance: FactoryInstance by injectLazy()
|
||||
private val singleton: SingletonInstance by injectValue()
|
||||
private val lazySingleton: SingletonInstance by injectLazy()
|
||||
|
||||
fun run() {
|
||||
for (i in 1..5) {
|
||||
LOG.info("Instance {}: {}", i, instance)
|
||||
}
|
||||
for (i in 1..5) {
|
||||
LOG.info("Lazy Instance {}: {}", i, lazyInstance)
|
||||
}
|
||||
for (i in 1..5) {
|
||||
LOG.info("Singleton {}: {}", i, singleton)
|
||||
}
|
||||
for (i in 1..5) {
|
||||
LOG.info("Lazy Singleton {}: {}", i, lazySingleton)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun run() {
|
||||
Injekt.get<App>().run()
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package com.baeldung.injekt
|
||||
|
||||
import org.slf4j.LoggerFactory
|
||||
import uy.kohesive.injekt.*
|
||||
import uy.kohesive.injekt.api.*
|
||||
|
||||
class KeyedApplication {
|
||||
companion object : InjektMain() {
|
||||
private val LOG = LoggerFactory.getLogger(KeyedApplication::class.java)
|
||||
@JvmStatic fun main(args: Array<String>) {
|
||||
KeyedApplication().run()
|
||||
}
|
||||
|
||||
override fun InjektRegistrar.registerInjectables() {
|
||||
val configs = mapOf(
|
||||
"google" to Config("googleClientId", "googleClientSecret"),
|
||||
"twitter" to Config("twitterClientId", "twitterClientSecret")
|
||||
)
|
||||
addPerKeyFactory<Config, String> {key -> configs[key]!! }
|
||||
|
||||
addSingletonFactory { App() }
|
||||
}
|
||||
}
|
||||
|
||||
data class Config(val clientId: String, val clientSecret: String)
|
||||
|
||||
class App {
|
||||
fun run() {
|
||||
LOG.info("Google config: {}", Injekt.get<Config>("google"))
|
||||
LOG.info("Twitter config: {}", Injekt.get<Config>("twitter"))
|
||||
}
|
||||
}
|
||||
|
||||
fun run() {
|
||||
Injekt.get<App>().run()
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
package com.baeldung.injekt
|
||||
|
||||
import org.slf4j.LoggerFactory
|
||||
import uy.kohesive.injekt.*
|
||||
import uy.kohesive.injekt.api.*
|
||||
|
||||
class ModularApplication {
|
||||
class ConfigModule(private val port: Int) : InjektModule {
|
||||
override fun InjektRegistrar.registerInjectables() {
|
||||
addSingleton(Config(port))
|
||||
}
|
||||
}
|
||||
|
||||
object ServerModule : InjektModule {
|
||||
override fun InjektRegistrar.registerInjectables() {
|
||||
addSingletonFactory { Server(Injekt.get()) }
|
||||
}
|
||||
}
|
||||
|
||||
companion object : InjektMain() {
|
||||
private val LOG = LoggerFactory.getLogger(Server::class.java)
|
||||
@JvmStatic fun main(args: Array<String>) {
|
||||
ModularApplication().run()
|
||||
}
|
||||
|
||||
override fun InjektRegistrar.registerInjectables() {
|
||||
importModule(ConfigModule(12345))
|
||||
importModule(ServerModule)
|
||||
}
|
||||
}
|
||||
|
||||
data class Config(
|
||||
val port: Int
|
||||
)
|
||||
|
||||
class Server(private val config: Config) {
|
||||
|
||||
fun start() {
|
||||
LOG.info("Starting server on ${config.port}")
|
||||
}
|
||||
}
|
||||
|
||||
fun run() {
|
||||
Injekt.get<Server>().start()
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
package com.baeldung.injekt
|
||||
|
||||
import org.slf4j.LoggerFactory
|
||||
import uy.kohesive.injekt.*
|
||||
import uy.kohesive.injekt.api.*
|
||||
import java.util.*
|
||||
import java.util.concurrent.Executors
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class PerThreadApplication {
|
||||
companion object : InjektMain() {
|
||||
private val LOG = LoggerFactory.getLogger(PerThreadApplication::class.java)
|
||||
@JvmStatic fun main(args: Array<String>) {
|
||||
PerThreadApplication().run()
|
||||
}
|
||||
|
||||
override fun InjektRegistrar.registerInjectables() {
|
||||
addPerThreadFactory {
|
||||
val value = FactoryInstance(UUID.randomUUID().toString())
|
||||
LOG.info("Constructing instance: {}", value)
|
||||
value
|
||||
}
|
||||
|
||||
addSingletonFactory { App() }
|
||||
}
|
||||
}
|
||||
|
||||
data class FactoryInstance(val value: String)
|
||||
|
||||
class App {
|
||||
fun run() {
|
||||
val threadPool = Executors.newFixedThreadPool(5)
|
||||
|
||||
for (i in 1..20) {
|
||||
threadPool.submit {
|
||||
val instance = Injekt.get<FactoryInstance>()
|
||||
LOG.info("Value for thread {}: {}", Thread.currentThread().id, instance)
|
||||
TimeUnit.MILLISECONDS.sleep(100)
|
||||
}
|
||||
}
|
||||
threadPool.awaitTermination(10, TimeUnit.SECONDS)
|
||||
}
|
||||
}
|
||||
|
||||
fun run() {
|
||||
Injekt.get<App>().run()
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package com.baeldung.injekt
|
||||
|
||||
import org.slf4j.LoggerFactory
|
||||
import uy.kohesive.injekt.*
|
||||
import uy.kohesive.injekt.api.*
|
||||
|
||||
class SimpleApplication {
|
||||
companion object : InjektMain() {
|
||||
private val LOG = LoggerFactory.getLogger(Server::class.java)
|
||||
@JvmStatic fun main(args: Array<String>) {
|
||||
SimpleApplication().run()
|
||||
}
|
||||
|
||||
override fun InjektRegistrar.registerInjectables() {
|
||||
addSingleton(Config(12345))
|
||||
addSingletonFactory { Server(Injekt.get()) }
|
||||
}
|
||||
}
|
||||
|
||||
data class Config(
|
||||
val port: Int
|
||||
)
|
||||
|
||||
class Server(private val config: Config) {
|
||||
|
||||
fun start() {
|
||||
LOG.info("Starting server on ${config.port}")
|
||||
}
|
||||
}
|
||||
|
||||
fun run() {
|
||||
Injekt.get<Server>().start()
|
||||
}
|
||||
}
|
@ -22,22 +22,22 @@ class UserTest {
|
||||
|
||||
private fun buildUser(): User {
|
||||
return User(
|
||||
"Java",
|
||||
"Duke",
|
||||
"Javastreet",
|
||||
"42",
|
||||
"1234567",
|
||||
30,
|
||||
"s3cr37"
|
||||
"Java",
|
||||
"Duke",
|
||||
"Javastreet",
|
||||
"42",
|
||||
"1234567",
|
||||
30,
|
||||
"s3cr37"
|
||||
)
|
||||
}
|
||||
|
||||
private fun assertUserView(pr: UserView) {
|
||||
assertAll(
|
||||
{ assertEquals("Java Duke", pr.name) },
|
||||
{ assertEquals("Javastreet 42", pr.address) },
|
||||
{ assertEquals("1234567", pr.telephone) },
|
||||
{ assertEquals(30, pr.age) }
|
||||
{ assertEquals("Java Duke", pr.name) },
|
||||
{ assertEquals("Javastreet 42", pr.address) },
|
||||
{ assertEquals("1234567", pr.telephone) },
|
||||
{ assertEquals(30, pr.age) }
|
||||
)
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package org.baeldung.caching.eviction.controllers;
|
||||
|
||||
import org.baeldung.caching.eviction.service.CachingService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
public class CachingController {
|
||||
|
||||
@Autowired
|
||||
CachingService cachingService;
|
||||
|
||||
@GetMapping("clearAllCaches")
|
||||
public void clearAllCaches() {
|
||||
cachingService.evictAllCaches();
|
||||
}
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
package org.baeldung.caching.eviction.service;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.cache.annotation.CacheEvict;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class CachingService {
|
||||
|
||||
@Autowired
|
||||
CacheManager cacheManager;
|
||||
|
||||
public void putToCache(String cacheName, String key, String value) {
|
||||
cacheManager.getCache(cacheName).put(key, value);
|
||||
}
|
||||
|
||||
public String getFromCache(String cacheName, String key) {
|
||||
String value = null;
|
||||
if (cacheManager.getCache(cacheName).get(key) != null) {
|
||||
value = cacheManager.getCache(cacheName).get(key).get().toString();
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@CacheEvict(value = "first", key = "#cacheKey")
|
||||
public void evictSingleCacheValue(String cacheKey) {
|
||||
}
|
||||
|
||||
@CacheEvict(value = "first", allEntries = true)
|
||||
public void evictAllCacheValues() {
|
||||
}
|
||||
|
||||
public void evictSingleCacheValue(String cacheName, String cacheKey) {
|
||||
cacheManager.getCache(cacheName).evict(cacheKey);
|
||||
}
|
||||
|
||||
public void evictAllCacheValues(String cacheName) {
|
||||
cacheManager.getCache(cacheName).clear();
|
||||
}
|
||||
|
||||
public void evictAllCaches() {
|
||||
cacheManager.getCacheNames()
|
||||
.parallelStream()
|
||||
.forEach(cacheName -> cacheManager.getCache(cacheName).clear());
|
||||
}
|
||||
|
||||
@Scheduled(fixedRate = 6000)
|
||||
public void evictAllcachesAtIntervals() {
|
||||
evictAllCaches();
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
package org.baeldung.nullibility;
|
||||
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
public class Person {
|
||||
@NonNull
|
||||
private String fullName;
|
||||
@Nullable
|
||||
private String nickName;
|
||||
|
||||
void setFullName(String fullName) {
|
||||
if (fullName != null && fullName.isEmpty()) {
|
||||
fullName = null;
|
||||
}
|
||||
this.fullName = fullName;
|
||||
}
|
||||
|
||||
void setNickName(String nickName) {
|
||||
if (nickName != null && nickName.isEmpty()) {
|
||||
nickName = null;
|
||||
}
|
||||
this.nickName = nickName;
|
||||
}
|
||||
|
||||
String getFullName() {
|
||||
return fullName;
|
||||
}
|
||||
|
||||
String getNickName() {
|
||||
return nickName;
|
||||
}
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
@NonNullApi
|
||||
@NonNullFields
|
||||
package org.baeldung.nullibility;
|
||||
|
||||
import org.springframework.lang.NonNullApi;
|
||||
import org.springframework.lang.NonNullFields;
|
@ -0,0 +1,79 @@
|
||||
package org.baeldung.caching.test;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.CoreMatchers.nullValue;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.baeldung.caching.eviction.service.CachingService;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.cache.annotation.EnableCaching;
|
||||
import org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean;
|
||||
import org.springframework.cache.support.SimpleCacheManager;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration
|
||||
public class CacheEvictAnnotationIntegrationTest {
|
||||
|
||||
@Configuration
|
||||
@EnableCaching
|
||||
static class ContextConfiguration {
|
||||
|
||||
@Bean
|
||||
public CachingService cachingService() {
|
||||
return new CachingService();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public CacheManager cacheManager(){
|
||||
SimpleCacheManager cacheManager = new SimpleCacheManager();
|
||||
List<Cache> caches = new ArrayList<>();
|
||||
caches.add(cacheBean().getObject());
|
||||
cacheManager.setCaches(caches );
|
||||
return cacheManager;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ConcurrentMapCacheFactoryBean cacheBean(){
|
||||
ConcurrentMapCacheFactoryBean cacheFactoryBean = new ConcurrentMapCacheFactoryBean();
|
||||
cacheFactoryBean.setName("first");
|
||||
return cacheFactoryBean;
|
||||
}
|
||||
}
|
||||
|
||||
@Autowired
|
||||
CachingService cachingService;
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
cachingService.putToCache("first", "key1", "Baeldung");
|
||||
cachingService.putToCache("first", "key2", "Article");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenFirstCache_whenSingleCacheValueEvictRequested_thenEmptyCacheValue() {
|
||||
cachingService.evictSingleCacheValue("key1");
|
||||
String key1 = cachingService.getFromCache("first", "key1");
|
||||
assertThat(key1, is(nullValue()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenFirstCache_whenAllCacheValueEvictRequested_thenEmptyCache() {
|
||||
cachingService.evictAllCacheValues();
|
||||
String key1 = cachingService.getFromCache("first", "key1");
|
||||
String key2 = cachingService.getFromCache("first", "key2");
|
||||
assertThat(key1, is(nullValue()));
|
||||
assertThat(key2, is(nullValue()));
|
||||
}
|
||||
}
|
@ -0,0 +1,96 @@
|
||||
package org.baeldung.caching.test;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.CoreMatchers.nullValue;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.baeldung.caching.eviction.service.CachingService;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean;
|
||||
import org.springframework.cache.support.SimpleCacheManager;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration
|
||||
public class CacheManagerEvictIntegrationTest {
|
||||
|
||||
@Configuration
|
||||
static class ContextConfiguration {
|
||||
|
||||
@Bean
|
||||
public CachingService cachingService() {
|
||||
return new CachingService();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public CacheManager cacheManager(){
|
||||
SimpleCacheManager cacheManager = new SimpleCacheManager();
|
||||
List<Cache> caches = new ArrayList<>();
|
||||
caches.add(cacheBeanFirst().getObject());
|
||||
caches.add(cacheBeanSecond().getObject());
|
||||
cacheManager.setCaches(caches );
|
||||
return cacheManager;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ConcurrentMapCacheFactoryBean cacheBeanFirst(){
|
||||
ConcurrentMapCacheFactoryBean cacheFactoryBean = new ConcurrentMapCacheFactoryBean();
|
||||
cacheFactoryBean.setName("first");
|
||||
return cacheFactoryBean;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ConcurrentMapCacheFactoryBean cacheBeanSecond(){
|
||||
ConcurrentMapCacheFactoryBean cacheFactoryBean = new ConcurrentMapCacheFactoryBean();
|
||||
cacheFactoryBean.setName("second");
|
||||
return cacheFactoryBean;
|
||||
}
|
||||
}
|
||||
|
||||
@Autowired
|
||||
CachingService cachingService;
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
cachingService.putToCache("first", "key1", "Baeldung");
|
||||
cachingService.putToCache("first", "key2", "Article");
|
||||
cachingService.putToCache("second", "key", "Article");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenFirstCache_whenSingleCacheValueEvictRequested_thenEmptyCacheValue() {
|
||||
cachingService.evictSingleCacheValue("first", "key1");
|
||||
String key1 = cachingService.getFromCache("first", "key1");
|
||||
assertThat(key1, is(nullValue()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenFirstCache_whenAllCacheValueEvictRequested_thenEmptyCache() {
|
||||
cachingService.evictAllCacheValues("first");
|
||||
String key1 = cachingService.getFromCache("first", "key1");
|
||||
String key2 = cachingService.getFromCache("first", "key2");
|
||||
assertThat(key1, is(nullValue()));
|
||||
assertThat(key2, is(nullValue()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenAllCaches_whenAllCacheEvictRequested_thenEmptyAllCaches() {
|
||||
cachingService.evictAllCaches();
|
||||
String key1 = cachingService.getFromCache("first", "key1");
|
||||
assertThat(key1, is(nullValue()));
|
||||
|
||||
String key = cachingService.getFromCache("second", "key");
|
||||
assertThat(key, is(nullValue()));
|
||||
}
|
||||
}
|
65
spring-boot-crud/pom.xml
Normal file
65
spring-boot-crud/pom.xml
Normal file
@ -0,0 +1,65 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>com.baeldung.spring-boot-crud</groupId>
|
||||
<artifactId>spring-boot-crud</artifactId>
|
||||
<version>0.1.0</version>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>2.0.6.RELEASE</version>
|
||||
</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>
|
||||
</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>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<java.version>1.8</java.version>
|
||||
</properties>
|
||||
|
||||
<build>
|
||||
<finalName>spring-boot-crud</finalName>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
<filtering>true</filtering>
|
||||
</resource>
|
||||
</resources>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
@ -0,0 +1,24 @@
|
||||
package com.baeldung.crud;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.domain.EntityScan;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
|
||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
|
||||
@SpringBootApplication
|
||||
@EnableAutoConfiguration
|
||||
@ComponentScan(basePackages={"com.baeldung.crud"})
|
||||
@EnableJpaRepositories(basePackages="com.baeldung.crud.repositories")
|
||||
@EnableTransactionManagement
|
||||
@EntityScan(basePackages="com.baeldung.crud.entities")
|
||||
|
||||
@SpringBootApplication
|
||||
public class Application {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(Application.class, args);
|
||||
}
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
package com.baeldung.crud.controllers;
|
||||
|
||||
import com.baeldung.crud.UserRepository;
|
||||
import com.baeldung.crud.entities.User;
|
||||
import javax.validation.Valid;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
|
||||
@Controller
|
||||
public class UserController {
|
||||
|
||||
private final UserRepository userRepository;
|
||||
|
||||
@Autowired
|
||||
public UserController(UserRepository userRepository) {
|
||||
this.userRepository = userRepository;
|
||||
}
|
||||
|
||||
@GetMapping("/signup")
|
||||
public String showSignUpForm(User user) {
|
||||
return "add-user";
|
||||
}
|
||||
|
||||
@PostMapping("/adduser")
|
||||
public String addUser(@Valid User user, BindingResult result, Model model) {
|
||||
if (result.hasErrors()) {
|
||||
return "add-user";
|
||||
}
|
||||
|
||||
userRepository.save(user);
|
||||
model.addAttribute("users", userRepository.findAll());
|
||||
return "index";
|
||||
}
|
||||
|
||||
@GetMapping("/edit/{id}")
|
||||
public String showUpdateForm(@PathVariable("id") long id, Model model) {
|
||||
User user = userRepository.findById(id).orElseThrow(() -> new IllegalArgumentException("Invalid user Id:" + id));
|
||||
model.addAttribute("user", user);
|
||||
return "update-user";
|
||||
}
|
||||
|
||||
@PostMapping("/update/{id}")
|
||||
public String updateUser(@PathVariable("id") long id, @Valid User user, BindingResult result, Model model) {
|
||||
if (result.hasErrors()) {
|
||||
user.setId(id);
|
||||
return "update-user";
|
||||
}
|
||||
|
||||
userRepository.save(user);
|
||||
model.addAttribute("users", userRepository.findAll());
|
||||
return "index";
|
||||
}
|
||||
|
||||
@GetMapping("/delete/{id}")
|
||||
public String deleteUser(@PathVariable("id") long id, Model model) {
|
||||
User user = userRepository.findById(id).orElseThrow(() -> new IllegalArgumentException("Invalid user Id:" + id));
|
||||
userRepository.delete(user);
|
||||
model.addAttribute("users", userRepository.findAll());
|
||||
return "index";
|
||||
}
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
package com.baeldung.crud.entities;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
|
||||
@Entity
|
||||
public class User {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
private long id;
|
||||
@NotBlank(message = "Name is mandatory")
|
||||
private String name;
|
||||
|
||||
@NotBlank(message = "Email is mandatory")
|
||||
private String email;
|
||||
|
||||
public User() {}
|
||||
|
||||
public User(String name, String email) {
|
||||
this.name = name;
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
public void setId(long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public void setEmail(String email) {
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "User{" + "id=" + id + ", name=" + name + ", email=" + email + '}';
|
||||
}
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package com.baeldung.crud.repositories;
|
||||
|
||||
import com.baeldung.crud.entities.User;
|
||||
import java.util.List;
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public interface UserRepository extends CrudRepository<User, Long> {
|
||||
|
||||
List<User> findByName(String name);
|
||||
|
||||
}
|
2
spring-boot-crud/src/main/resources/css/shards.min.css
vendored
Normal file
2
spring-boot-crud/src/main/resources/css/shards.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
40
spring-boot-crud/src/main/resources/templates/add-user.html
Normal file
40
spring-boot-crud/src/main/resources/templates/add-user.html
Normal file
@ -0,0 +1,40 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns:th="http://www.thymeleaf.org">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="x-ua-compatible" content="ie=edge">
|
||||
<title>Add User</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
|
||||
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.4.1/css/all.css" integrity="sha384-5sAR7xN1Nv6T6+dT2mhtzEpVJvfS3NScPQTrOxhwjIuvcA67KV2R5Jz6kr4abQsz" crossorigin="anonymous">
|
||||
<link rel="stylesheet" href="../css/shards.min.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="container my-5">
|
||||
<h2 class="mb-5">New User</h2>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<form action="#" th:action="@{/adduser}" th:object="${user}" method="post">
|
||||
<div class="row">
|
||||
<div class="form-group col-md-6">
|
||||
<label for="name" class="col-form-label">Name</label>
|
||||
<input type="text" th:field="*{name}" class="form-control" id="name" placeholder="Name">
|
||||
<span th:if="${#fields.hasErrors('name')}" th:errors="*{name}" class="text-danger"></span>
|
||||
</div>
|
||||
<div class="form-group col-md-6">
|
||||
<label for="email" class="col-form-label">Email</label>
|
||||
<input type="text" th:field="*{email}" class="form-control" id="email" placeholder="Email">
|
||||
<span th:if="${#fields.hasErrors('email')}" th:errors="*{email}" class="text-danger"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6 mt-5">
|
||||
<input type="submit" class="btn btn-primary" value="Add User">
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
43
spring-boot-crud/src/main/resources/templates/index.html
Normal file
43
spring-boot-crud/src/main/resources/templates/index.html
Normal file
@ -0,0 +1,43 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns:th="http://www.thymeleaf.org">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="x-ua-compatible" content="ie=edge">
|
||||
<title>Users</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
|
||||
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.4.1/css/all.css" integrity="sha384-5sAR7xN1Nv6T6+dT2mhtzEpVJvfS3NScPQTrOxhwjIuvcA67KV2R5Jz6kr4abQsz" crossorigin="anonymous">
|
||||
<link rel="stylesheet" href="../css/shards.min.css">
|
||||
</head>
|
||||
<body>
|
||||
<div th:switch="${users}" class="container my-5">
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<h2 th:case="null">No users yet!</h2>
|
||||
<div th:case="*">
|
||||
<h2 class="my-5">Users</h2>
|
||||
<table class="table table-striped table-responsive-md">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Email</th>
|
||||
<th>Edit</th>
|
||||
<th>Delete</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr th:each="user : ${users}">
|
||||
<td th:text="${user.name}"></td>
|
||||
<td th:text="${user.email}"></td>
|
||||
<td><a th:href="@{/edit/{id}(id=${user.id})}" class="btn btn-primary"><i class="fas fa-user-edit ml-2"></i></a></td>
|
||||
<td><a th:href="@{/delete/{id}(id=${user.id})}" class="btn btn-primary"><i class="fas fa-user-times ml-2"></i></a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<p class="my-5"><a href="/signup" class="btn btn-primary"><i class="fas fa-user-plus ml-2"></i></a></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,40 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns:th="http://www.thymeleaf.org">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="x-ua-compatible" content="ie=edge">
|
||||
<title>Update User</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
|
||||
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.4.1/css/all.css" integrity="sha384-5sAR7xN1Nv6T6+dT2mhtzEpVJvfS3NScPQTrOxhwjIuvcA67KV2R5Jz6kr4abQsz" crossorigin="anonymous">
|
||||
<link rel="stylesheet" href="../css/shards.min.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="container my-5">
|
||||
<h2 class="mb-5">Update User</h2>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<form action="#" th:action="@{/update/{id}(id=${user.id})}" th:object="${user}" method="post">
|
||||
<div class="row">
|
||||
<div class="form-group col-md-6">
|
||||
<label for="name" class="col-form-label">Name</label>
|
||||
<input type="text" th:field="*{name}" class="form-control" id="name" placeholder="Name">
|
||||
<span th:if="${#fields.hasErrors('name')}" th:errors="*{name}" class="text-danger"></span>
|
||||
</div>
|
||||
<div class="form-group col-md-6">
|
||||
<label for="email" class="col-form-label">Email</label>
|
||||
<input type="text" th:field="*{email}" class="form-control" id="email" placeholder="Email">
|
||||
<span th:if="${#fields.hasErrors('email')}" th:errors="*{email}" class="text-danger"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6 mt-5">
|
||||
<input type="submit" class="btn btn-primary" value="Update User">
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,81 @@
|
||||
package com.baeldung.crud;
|
||||
|
||||
import com.baeldung.crud.UserController;
|
||||
import com.baeldung.crud.entities.User;
|
||||
import com.baeldung.crud.UserRepository;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.validation.BindingResult;
|
||||
|
||||
public class UserControllerUnitTest {
|
||||
|
||||
private static UserController userController;
|
||||
private static UserRepository mockedUserRepository;
|
||||
private static BindingResult mockedBindingResult;
|
||||
private static Model mockedModel;
|
||||
|
||||
@BeforeClass
|
||||
public static void setUpUserControllerInstance() {
|
||||
mockedUserRepository = mock(UserRepository.class);
|
||||
mockedBindingResult = mock(BindingResult.class);
|
||||
mockedModel = mock(Model.class);
|
||||
userController = new UserController(mockedUserRepository);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenCalledshowSignUpForm_thenCorrect() {
|
||||
User user = new User("John", "john@domain.com");
|
||||
|
||||
assertThat(userController.showSignUpForm(user)).isEqualTo("add-user");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenCalledaddUserAndValidUser_thenCorrect() {
|
||||
User user = new User("John", "john@domain.com");
|
||||
|
||||
when(mockedBindingResult.hasErrors()).thenReturn(false);
|
||||
|
||||
assertThat(userController.addUser(user, mockedBindingResult, mockedModel)).isEqualTo("index");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenCalledaddUserAndInValidUser_thenCorrect() {
|
||||
User user = new User("John", "john@domain.com");
|
||||
|
||||
when(mockedBindingResult.hasErrors()).thenReturn(true);
|
||||
|
||||
assertThat(userController.addUser(user, mockedBindingResult, mockedModel)).isEqualTo("add-user");
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void whenCalledshowUpdateForm_thenIllegalArgumentException() {
|
||||
assertThat(userController.showUpdateForm(0, mockedModel)).isEqualTo("update-user");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenCalledupdateUserAndValidUser_thenCorrect() {
|
||||
User user = new User("John", "john@domain.com");
|
||||
|
||||
when(mockedBindingResult.hasErrors()).thenReturn(false);
|
||||
|
||||
assertThat(userController.updateUser(1l, user, mockedBindingResult, mockedModel)).isEqualTo("index");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenCalledupdateUserAndInValidUser_thenCorrect() {
|
||||
User user = new User("John", "john@domain.com");
|
||||
|
||||
when(mockedBindingResult.hasErrors()).thenReturn(true);
|
||||
|
||||
assertThat(userController.updateUser(1l, user, mockedBindingResult, mockedModel)).isEqualTo("update-user");
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void whenCalleddeleteUser_thenIllegalArgumentException() {
|
||||
assertThat(userController.deleteUser(1l, mockedModel)).isEqualTo("index");
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
package com.baeldung.crud;
|
||||
|
||||
import com.baeldung.crud.User;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import org.junit.Test;
|
||||
|
||||
public class UserUnitTest {
|
||||
|
||||
@Test
|
||||
public void whenCalledGetName_thenCorrect() {
|
||||
User user = new User("Julie", "julie@domain.com");
|
||||
|
||||
assertThat(user.getName()).isEqualTo("Julie");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenCalledGetEmail_thenCorrect() {
|
||||
User user = new User("Julie", "julie@domain.com");
|
||||
|
||||
assertThat(user.getEmail()).isEqualTo("julie@domain.com");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenCalledSetName_thenCorrect() {
|
||||
User user = new User("Julie", "julie@domain.com");
|
||||
|
||||
user.setName("John");
|
||||
|
||||
assertThat(user.getName()).isEqualTo("John");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenCalledSetEmail_thenCorrect() {
|
||||
User user = new User("Julie", "julie@domain.com");
|
||||
|
||||
user.setEmail("john@domain.com");
|
||||
|
||||
assertThat(user.getEmail()).isEqualTo("john@domain.com");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenCalledtoString_thenCorrect() {
|
||||
User user = new User("Julie", "julie@domain.com");
|
||||
assertThat(user.toString()).isEqualTo("User{id=0, name=Julie, email=julie@domain.com}");
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user