Merge remote-tracking branch 'upstream/master' into tutorials/binaryTreeJava

This commit is contained in:
Marcos 2017-12-07 23:38:58 +01:00
commit 9f3ce63cd9
60 changed files with 1882 additions and 708 deletions

View File

@ -83,6 +83,24 @@
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-core</artifactId>
<version>1.19</version>
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-annprocess</artifactId>
<version>1.19</version>
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-bytecode</artifactId>
<version>1.19</version>
</dependency>
</dependencies>
<build>

View File

@ -0,0 +1,45 @@
package com.baeldung.counter;
import java.util.HashMap;
import java.util.Map;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Fork;
import org.openjdk.jmh.annotations.Mode;
import com.baeldung.counter.CounterUtil.MutableInteger;
@Fork(value = 1, warmups = 3)
@BenchmarkMode(Mode.All)
public class CounterStatistics {
private static final Map<String, Integer> counterMap = new HashMap<>();
private static final Map<String, MutableInteger> counterWithMutableIntMap = new HashMap<>();
private static final Map<String, int[]> counterWithIntArrayMap = new HashMap<>();
private static final Map<String, Long> counterWithLongWrapperMap = new HashMap<>();
@Benchmark
public void wrapperAsCounter() {
CounterUtil.counterWithWrapperObject(counterMap);
}
@Benchmark
public void lambdaExpressionWithWrapper() {
CounterUtil.counterWithLambdaAndWrapper(counterWithLongWrapperMap);
}
@Benchmark
public void mutableIntegerAsCounter() {
CounterUtil.counterWithMutableInteger(counterWithMutableIntMap);
}
@Benchmark
public void primitiveArrayAsCounter() {
CounterUtil.counterWithPrimitiveArray(counterWithIntArrayMap);
}
public static void main(String[] args) throws Exception {
org.openjdk.jmh.Main.main(args);
}
}

View File

@ -0,0 +1,53 @@
package com.baeldung.counter;
import java.util.HashMap;
import java.util.Map;
import static org.junit.Assert.*;
import org.junit.Test;
import com.baeldung.counter.CounterUtil.MutableInteger;
public class CounterTest {
@Test
public void whenMapWithWrapperAsCounter_runsSuccessfully() {
Map<String, Integer> counterMap = new HashMap<>();
CounterUtil.counterWithWrapperObject(counterMap);
assertEquals(3, counterMap.get("China")
.intValue());
assertEquals(2, counterMap.get("India")
.intValue());
}
@Test
public void whenMapWithLambdaAndWrapperCounter_runsSuccessfully() {
Map<String, Long> counterMap = new HashMap<>();
CounterUtil.counterWithLambdaAndWrapper(counterMap);
assertEquals(3l, counterMap.get("China")
.longValue());
assertEquals(2l, counterMap.get("India")
.longValue());
}
@Test
public void whenMapWithMutableIntegerCounter_runsSuccessfully() {
Map<String, MutableInteger> counterMap = new HashMap<>();
CounterUtil.counterWithMutableInteger(counterMap);
assertEquals(3, counterMap.get("China")
.getCount());
assertEquals(2, counterMap.get("India")
.getCount());
}
@Test
public void whenMapWithPrimitiveArray_runsSuccessfully() {
Map<String, int[]> counterMap = new HashMap<>();
CounterUtil.counterWithPrimitiveArray(counterMap);
assertEquals(3, counterMap.get("China")[0]);
assertEquals(2, counterMap.get("India")[0]);
}
}

View File

@ -0,0 +1,61 @@
package com.baeldung.counter;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class CounterUtil {
private final static String[] COUNTRY_NAMES = { "China", "Australia", "India", "USA", "USSR", "UK", "China", "France", "Poland", "Austria", "India", "USA", "Egypt", "China" };
public static void counterWithWrapperObject(Map<String, Integer> counterMap) {
for (String country : COUNTRY_NAMES) {
counterMap.compute(country, (k, v) -> v == null ? 1 : v + 1);
}
}
public static void counterWithLambdaAndWrapper(Map<String, Long> counterMap) {
counterMap.putAll(Stream.of(COUNTRY_NAMES)
.parallel()
.collect(Collectors.groupingBy(k -> k, Collectors.counting())));
}
public static class MutableInteger {
int count;
public MutableInteger(int count) {
this.count = count;
}
public void increment() {
this.count++;
}
public int getCount() {
return this.count;
}
}
public static void counterWithMutableInteger(Map<String, MutableInteger> counterMap) {
for (String country : COUNTRY_NAMES) {
MutableInteger oldValue = counterMap.get(country);
if (oldValue != null) {
oldValue.increment();
} else {
counterMap.put(country, new MutableInteger(1));
}
}
}
public static void counterWithPrimitiveArray(Map<String, int[]> counterMap) {
for (String country : COUNTRY_NAMES) {
int[] oldCounter = counterMap.get(country);
if (oldCounter != null) {
oldCounter[0] += 1;
} else {
counterMap.put(country, new int[] { 1 });
}
}
}
}

View File

@ -9,7 +9,6 @@ import java.util.List;
import java.util.concurrent.*;
import static junit.framework.TestCase.assertTrue;
import static org.junit.Assert.fail;
public class WaitingForThreadsToFinishTest {
@ -40,9 +39,7 @@ public class WaitingForThreadsToFinishTest {
CountDownLatch latch = new CountDownLatch(2);
for (int i = 0; i < 2; i++) {
WORKER_THREAD_POOL.submit(new Runnable() {
@Override
public void run() {
WORKER_THREAD_POOL.submit(() -> {
try {
Thread.sleep(1000);
latch.countDown();
@ -50,7 +47,6 @@ public class WaitingForThreadsToFinishTest {
e.printStackTrace();
Thread.currentThread().interrupt();
}
}
});
}
@ -83,13 +79,9 @@ public class WaitingForThreadsToFinishTest {
awaitTerminationAfterShutdown(WORKER_THREAD_POOL);
try {
WORKER_THREAD_POOL.submit(new Callable<String>() {
@Override
public String call() throws Exception {
fail("This thread should have been rejected !");
WORKER_THREAD_POOL.submit((Callable<String>) () -> {
Thread.sleep(1000000);
return null;
}
});
} catch (RejectedExecutionException ex) {
//

View File

@ -0,0 +1,41 @@
package com.baeldung.array;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.IntStream;
import org.apache.commons.lang3.ArrayUtils;
import com.google.common.collect.Lists;
public class ArrayInverter {
public void invertUsingFor(Object[] array) {
for (int i = 0; i < array.length / 2; i++) {
Object temp = array[i];
array[i] = array[array.length - 1 - i];
array[array.length - 1 - i] = temp;
}
}
public void invertUsingCollectionsReverse(Object[] array) {
List<Object> list = Arrays.asList(array);
Collections.reverse(list);
}
public Object[] invertUsingStreams(final Object[] array) {
return IntStream.range(1, array.length + 1).mapToObj(i -> array[array.length - i]).toArray();
}
public void invertUsingCommonsLang(Object[] array) {
ArrayUtils.reverse(array);
}
public Object[] invertUsingGuava(Object[] array) {
List<Object> list = Arrays.asList(array);
List<Object> reverted = Lists.reverse(list);
return reverted.toArray();
}
}

View File

@ -54,7 +54,7 @@ public class GenericFile {
}
public String getFileInfo() {
return "File Name: " + this.getName() + "\n" + "Extension: " + this.getExtension() + "\n" + "Date Created: " + this.getDateCreated() + "\n" + "Version: " + this.getVersion() + "\n";
return String.format("File Name: %s\n" + " Extension: %s\n" + " Date Created: %s\n" + " Version: %s\n", this.getName(), this.getExtension(), this.getDateCreated(), this.getVersion());
}
public Object read() {

View File

@ -30,7 +30,7 @@ public class ImageFile extends GenericFile {
}
public String getFileInfo() {
return super.getFileInfo() + "Height: " + this.getHeight() + "\n" + "Width: " + this.getWidth();
return String.format(" %s Height: %d\n Width: %d", super.getFileInfo(), this.getHeight(), this.getWidth());
}
public String read() {

View File

@ -21,7 +21,7 @@ public class TextFile extends GenericFile {
}
public String getFileInfo() {
return super.getFileInfo() + "Word Count: " + wordCount;
return String.format(" %s Word Count: %d", super.getFileInfo(), wordCount);
}
public String read() {

View File

@ -0,0 +1,49 @@
package com.baeldung.array;
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.Test;
public class ArrayInverterUnitTest {
private String[] fruits = { "apples", "tomatoes", "bananas", "guavas", "pineapples", "oranges" };
@Test
public void invertArrayWithForLoop() {
ArrayInverter inverter = new ArrayInverter();
inverter.invertUsingFor(fruits);
assertThat(new String[] { "oranges", "pineapples", "guavas", "bananas", "tomatoes", "apples" }).isEqualTo(fruits);
}
@Test
public void invertArrayWithCollectionsReverse() {
ArrayInverter inverter = new ArrayInverter();
inverter.invertUsingCollectionsReverse(fruits);
assertThat(new String[] { "oranges", "pineapples", "guavas", "bananas", "tomatoes", "apples" }).isEqualTo(fruits);
}
@Test
public void invertArrayWithStreams() {
ArrayInverter inverter = new ArrayInverter();
assertThat(new String[] { "oranges", "pineapples", "guavas", "bananas", "tomatoes", "apples" }).isEqualTo(inverter.invertUsingStreams(fruits));
}
@Test
public void invertArrayWithCommonsLang() {
ArrayInverter inverter = new ArrayInverter();
inverter.invertUsingCommonsLang(fruits);
assertThat(new String[] { "oranges", "pineapples", "guavas", "bananas", "tomatoes", "apples" }).isEqualTo(fruits);
}
@Test
public void invertArrayWithGuava() {
ArrayInverter inverter = new ArrayInverter();
assertThat(new String[] { "oranges", "pineapples", "guavas", "bananas", "tomatoes", "apples" }).isEqualTo(inverter.invertUsingGuava(fruits));
}
}

View File

@ -14,9 +14,9 @@ public class NewOuter {
public void run() {
System.out.println("a = " + a);
System.out.println("b = " + b);
System.out.println("NewOuterTest.this.a = " + NewOuter.this.a);
System.out.println("NewOuterTest.b = " + NewOuter.b);
System.out.println("NewOuterTest.this.b = " + NewOuter.this.b);
System.out.println("NewOuter.this.a = " + NewOuter.this.a);
System.out.println("NewOuter.b = " + NewOuter.b);
System.out.println("NewOuter.this.b = " + NewOuter.this.b);
}
}

View File

@ -3,8 +3,6 @@ package com.baeldung.polymorphism;
import static org.junit.Assert.*;
import java.awt.image.BufferedImage;
import org.junit.Ignore;
import org.junit.Test;
public class PolymorphismUnitTest {

View File

@ -0,0 +1,51 @@
package com.baeldung.kotlin
import org.junit.Assert
import org.junit.Test
class ExtensionMethods {
@Test
fun simpleExtensionMethod() {
fun String.escapeForXml() : String {
return this
.replace("&", "&amp;")
.replace("<", "&lt;")
.replace(">", "&gt;")
}
Assert.assertEquals("Nothing", "Nothing".escapeForXml())
Assert.assertEquals("&lt;Tag&gt;", "<Tag>".escapeForXml())
Assert.assertEquals("a&amp;b", "a&b".escapeForXml())
}
@Test
fun genericExtensionMethod() {
fun <T> T.concatAsString(b: T) : String {
return this.toString() + b.toString()
}
Assert.assertEquals("12", "1".concatAsString("2"))
Assert.assertEquals("12", 1.concatAsString(2))
// This doesn't compile
// Assert.assertEquals("12", 1.concatAsString(2.0))
}
@Test
fun infixExtensionMethod() {
infix fun Number.toPowerOf(exponent: Number): Double {
return Math.pow(this.toDouble(), exponent.toDouble())
}
Assert.assertEquals(9.0, 3 toPowerOf 2, 0.1)
Assert.assertEquals(3.0, 9 toPowerOf 0.5, 0.1)
}
@Test
fun operatorExtensionMethod() {
operator fun List<Int>.times(by: Int): List<Int> {
return this.map { it * by }
}
Assert.assertEquals(listOf(2, 4, 6), listOf(1, 2, 3) * 2)
}
}

View File

@ -0,0 +1,41 @@
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.github.jengelman.gradle.plugins:shadow:2.0.1'
}
}
apply plugin: 'java'
apply plugin: 'com.github.johnrengelman.shadow'
repositories {
mavenCentral()
}
jar {
manifest {
attributes "Main-Class": "com.baeldung.fatjar.Application"
}
from {
configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
}
}
task customFatJar(type: Jar) {
manifest {
attributes 'Main-Class': 'com.baeldung.fatjar.Application'
}
baseName = 'all-in-one-jar'
from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
with jar
}
dependencies{
compile group: 'org.slf4j', name: 'slf4j-api', version: '1.7.25'
compile group: 'org.slf4j', name: 'slf4j-simple', version: '1.7.25'
}

View File

@ -0,0 +1,16 @@
package com.baeldung.fatjar;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Application {
static final Logger logger = LoggerFactory.getLogger(Application.class);
public static void main(String[] args) {
logger.info("Hello at Baeldung!");
}
}

View File

@ -14,7 +14,9 @@ import org.junit.Test;
import javax.persistence.Query;
import java.io.IOException;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
public class HibernateSpatialTest {
@ -76,10 +78,8 @@ public class HibernateSpatialTest {
Query query = session.createQuery("select p from PointEntity p where within(p.point, :area) = true",
PointEntity.class);
query.setParameter("area", wktToGeometry("POLYGON((0 0, 0 5, 5 5, 5 0, 0 0))"));
assertEquals(3, query.getResultList().size());
assertEquals("POINT (1 1)", ((PointEntity) query.getResultList().get(0)).getPoint().toString());
assertEquals("POINT (1 2)", ((PointEntity) query.getResultList().get(1)).getPoint().toString());
assertEquals("POINT (3 4)", ((PointEntity) query.getResultList().get(2)).getPoint().toString());
assertThat(query.getResultList().stream().map(p -> ((PointEntity) p).getPoint().toString()))
.containsOnly("POINT (1 1)", "POINT (1 2)", "POINT (3 4)");
}
private void insertPoint(String point) throws ParseException {

BIN
libraries/helloWorld.docx Normal file

Binary file not shown.

View File

View File

@ -0,0 +1,35 @@
<?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>
<name>logback</name>
<artifactId>logback</artifactId>
<version>0.1-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<logback.version>1.2.3</logback.version>
</properties>
<parent>
<groupId>com.baeldung</groupId>
<artifactId>parent-modules</artifactId>
<version>1.0.0-SNAPSHOT</version>
<relativePath>../../</relativePath>
</parent>
<dependencies>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,14 @@
package com.baeldung.logback;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Example {
private static final Logger logger = LoggerFactory.getLogger(Example.class);
public static void main(String[] args) {
logger.info("Example log from {}", Example.class.getSimpleName());
}
}

View File

@ -0,0 +1,37 @@
package com.baeldung.logback;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.AppenderBase;
import java.util.HashMap;
import java.util.Map;
public class MapAppender extends AppenderBase<ILoggingEvent> {
private final Map<String, ILoggingEvent> eventMap = new HashMap<>();
private String prefix;
@Override
protected void append(final ILoggingEvent event) {
if (prefix == null || "".equals(prefix)) {
addError("Prefix is not set for MapAppender.");
return;
}
eventMap.put(prefix + System.currentTimeMillis(), event);
}
public String getPrefix() {
return prefix;
}
public void setPrefix(final String prefix) {
this.prefix = prefix;
}
public Map<String, ILoggingEvent> getEventMap() {
return eventMap;
}
}

View File

@ -0,0 +1,18 @@
<configuration>
<appender name="map" class="com.baeldung.logback.MapAppender">
<prefix>test</prefix>
</appender>
<appender name="out" 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="map"/>
<appender-ref ref="out"/>
</root>
</configuration>

View File

@ -0,0 +1,33 @@
package com.baeldung.logback;
import ch.qos.logback.classic.Logger;
import org.junit.Before;
import org.junit.Test;
import org.slf4j.LoggerFactory;
import static org.junit.Assert.assertEquals;
public class MapAppenderIntegrationTest {
private Logger rootLogger;
@Before
public void setUp() throws Exception {
rootLogger = (Logger) LoggerFactory.getLogger("ROOT");
}
@Test
public void whenLoggerEmitsLoggingEvent_thenAppenderReceivesEvent() throws Exception {
rootLogger.info("Test from {}", this.getClass().getSimpleName());
MapAppender appender = (MapAppender) rootLogger.getAppender("map");
assertEquals(appender.getEventMap().size(), 1);
}
@Test
public void givenNoPrefixSet_whenLoggerEmitsEvent_thenAppenderReceivesNoEvent() throws Exception {
rootLogger.info("Test from {}", this.getClass().getSimpleName());
MapAppender appender = (MapAppender) rootLogger.getAppender("badMap");
assertEquals(appender.getEventMap().size(), 0);
}
}

View File

@ -0,0 +1,60 @@
package com.baeldung.logback;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.spi.LoggingEvent;
import ch.qos.logback.core.BasicStatusManager;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
public class MapAppenderTest {
private LoggerContext ctx;
private MapAppender mapAppender = new MapAppender();
private LoggingEvent event;
@Before
public void setUp() throws Exception {
ctx = new LoggerContext();
ctx.setName("test context");
ctx.setStatusManager(new BasicStatusManager());
mapAppender.setContext(ctx);
mapAppender.setPrefix("prefix");
event = new LoggingEvent("fqcn", ctx.getLogger("logger"), Level.INFO, "Test message for logback appender", null, new Object[0]);
ctx.start();
}
@After
public void tearDown() throws Exception {
ctx.stop();
mapAppender.stop();
}
@Test
public void whenPrefixIsNull_thenMapAppenderDoesNotLog() throws Exception {
mapAppender.setPrefix(null);
mapAppender.append(event);
assertTrue(mapAppender.getEventMap().isEmpty());
}
@Test
public void whenPrefixIsEmpty_thenMapAppenderDoesNotLog() throws Exception {
mapAppender.setPrefix("");
mapAppender.append(event);
assertTrue(mapAppender.getEventMap().isEmpty());
}
@Test
public void whenLogMessageIsEmitted_thenMapAppenderReceivesMessage() throws Exception {
mapAppender.append(event);
assertEquals(mapAppender.getEventMap().size(), 1);
mapAppender.getEventMap().forEach((k, v) -> assertTrue(k.startsWith("prefix")));
}
}

View File

@ -0,0 +1,14 @@
<configuration debug="true">
<appender name="map" class="com.baeldung.logback.MapAppender">
<prefix>test</prefix>
</appender>
<appender name="badMap" class="com.baeldung.logback.MapAppender"/>
<root level="debug">
<appender-ref ref="map"/>
<appender-ref ref="badMap"/>
</root>
</configuration>

View File

@ -107,6 +107,7 @@
<module>logging-modules/log-mdc</module>
<module>logging-modules/log4j</module>
<module>logging-modules/log4j2</module>
<module>logging-modules/logback</module>
<module>lombok</module>
<!-- <module>kotlin</module>-->
<module>mapstruct</module>
@ -201,6 +202,7 @@
<module>spring-rest-query-language</module>
<module>spring-rest</module>
<module>spring-rest-simple</module>
<module>spring-security-acl</module>
<module>spring-security-cache-control</module>
<module>spring-security-client/spring-security-jsp-authentication</module>
<module>spring-security-client/spring-security-jsp-authorize</module>

View File

@ -14,7 +14,7 @@
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.0.M6</version>
<version>2.0.0.M7</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>

View File

@ -15,6 +15,7 @@
- [Intro to Spring Cloud Netflix - Hystrix](http://www.baeldung.com/spring-cloud-netflix-hystrix)
- [Dockerizing a Spring Boot Application](http://www.baeldung.com/dockerizing-spring-boot-application)
- [Introduction to Spring Cloud Rest Client with Netflix Ribbon](http://www.baeldung.com/spring-cloud-rest-client-with-netflix-ribbon)
- [A Quick Guide to Spring Cloud Consul](http://www.baeldung.com/spring-cloud-consul)
### Relevant Articles:
- [Introduction to Spring Cloud Rest Client with Netflix Ribbon](http://www.baeldung.com/spring-cloud-rest-client-with-netflix-ribbon)

View File

@ -1,59 +1,16 @@
package com.baeldung.spring.cloud.consul.discovery;
import java.net.URI;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication
@EnableDiscoveryClient
@RestController
public class DiscoveryClientApplication {
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
@Autowired
private DiscoveryClient discoveryClient;
@GetMapping("/discoveryClient")
public String home() {
return restTemplate().getForEntity(serviceUrl().resolve("/ping"), String.class)
.getBody();
}
@GetMapping("/ping")
public String ping() {
return "pong";
}
@RequestMapping("/my-health-check")
public ResponseEntity<String> myCustomCheck() {
return new ResponseEntity<>(HttpStatus.OK);
}
public URI serviceUrl() {
return discoveryClient.getInstances("myApp")
.stream()
.findFirst()
.map(si -> si.getUri())
.orElse(null);
}
public static void main(String[] args) {
new SpringApplicationBuilder(DiscoveryClientApplication.class).web(true)
.run(args);
}
}

View File

@ -0,0 +1,50 @@
package com.baeldung.spring.cloud.consul.discovery;
import java.net.URI;
import java.util.Optional;
import javax.naming.ServiceUnavailableException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;
@RestController
public class DiscoveryClientController {
@Autowired
private DiscoveryClient discoveryClient;
private final RestTemplate restTemplate = new RestTemplate();
@GetMapping("/discoveryClient")
public String discoveryPing() throws RestClientException, ServiceUnavailableException {
URI service = serviceUrl().map(s -> s.resolve("/ping"))
.orElseThrow(ServiceUnavailableException::new);
return restTemplate.getForEntity(service, String.class)
.getBody();
}
@GetMapping("/ping")
public String ping() {
return "pong";
}
@GetMapping("/my-health-check")
public ResponseEntity<String> myCustomCheck() {
return new ResponseEntity<>(HttpStatus.OK);
}
public Optional<URI> serviceUrl() {
return discoveryClient.getInstances("myApp")
.stream()
.findFirst()
.map(si -> si.getUri());
}
}

View File

@ -2,24 +2,9 @@ package com.baeldung.spring.cloud.consul.health;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@SpringBootApplication
@RestController
public class ServiceDiscoveryApplication {
@RequestMapping("/my-health-check")
public ResponseEntity<String> myCustomCheck() {
String message = "Testing my healh check function";
return new ResponseEntity<>(message, HttpStatus.FORBIDDEN);
}
@RequestMapping("/ping")
public String ping() {
return "pong";
}
public static void main(String[] args) {
new SpringApplicationBuilder(ServiceDiscoveryApplication.class).web(true)

View File

@ -0,0 +1,22 @@
package com.baeldung.spring.cloud.consul.health;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ServiceDiscoveryController {
@GetMapping("/ping")
public String ping() {
return "pong";
}
@GetMapping("/my-health-check")
public ResponseEntity<String> myCustomCheck() {
String message = "Testing my healh check function";
return new ResponseEntity<>(message, HttpStatus.FORBIDDEN);
}
}

View File

@ -1,34 +1,16 @@
package com.baeldung.spring.cloud.consul.properties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@SpringBootApplication
@RestController
public class DistributedPropertiesApplication {
@Value("${my.prop}")
String value;
@Autowired
private MyProperties properties;
@RequestMapping("/getConfigFromValue")
public String getConfigFromValue() {
return value;
}
@RequestMapping("/getConfigFromProperty")
public String getConfigFromProperty() {
return properties.getProp();
}
public static void main(String[] args) {
new SpringApplicationBuilder(DistributedPropertiesApplication.class).web(true)
.run(args);
}
}

View File

@ -0,0 +1,27 @@
package com.baeldung.spring.cloud.consul.properties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class DistributedPropertiesController {
@Value("${my.prop}")
String value;
@Autowired
private MyProperties properties;
@GetMapping("/getConfigFromValue")
public String getConfigFromValue() {
return value;
}
@GetMapping("/getConfigFromProperty")
public String getConfigFromProperty() {
return properties.getProp();
}
}

View File

@ -8,6 +8,7 @@ import org.springframework.context.annotation.Configuration;
@Configuration
@ConfigurationProperties("my")
public class MyProperties {
private String prop;
public String getProp() {
@ -17,4 +18,5 @@ public class MyProperties {
public void setProp(String prop) {
this.prop = prop;
}
}

View File

@ -1,47 +0,0 @@
package com.baeldung.spring.cloud.consul.ribbon;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication
@RestController
public class RibbonClientApplication {
@LoadBalanced
@Bean
RestTemplate getRestTemplate() {
return new RestTemplate();
}
@Autowired
RestTemplate restTemplate;
@RequestMapping("/ribbonClient")
public String home() {
return restTemplate.getForObject("http://myApp/ping", String.class);
}
@GetMapping("/ping")
public String ping() {
return "pong";
}
@RequestMapping("/my-health-check")
public ResponseEntity<String> myCustomCheck() {
return new ResponseEntity<>(HttpStatus.OK);
}
public static void main(String[] args) {
new SpringApplicationBuilder(RibbonClientApplication.class).web(true)
.run(args);
}
}

View File

@ -22,7 +22,7 @@
<spring-social.version>1.1.4.RELEASE</spring-social.version>
<javax-mail.version>1.4.7</javax-mail.version>
<javax-activation.version>1.1.1</javax-activation.version>
<junit.version>4.12</junit.version>
<maven-eclipse-plugin.version>2.10</maven-eclipse-plugin.version>
<exec-maven-plugin.version>1.5.0</exec-maven-plugin.version>
</properties>
@ -56,7 +56,7 @@
<artifactId>exec-maven-plugin</artifactId>
<version>${exec-maven-plugin.version}</version>
<configuration>
<mainClass>com.baeldung.samples.Main</mainClass>
<mainClass>com.baeldung.samples.FileCopyConfig</mainClass>
</configuration>
</plugin>
</plugins>
@ -106,6 +106,12 @@
<artifactId>spring-integration-file</artifactId>
<version>${spring.integration.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<profiles>

View File

@ -0,0 +1,4 @@
## Spring Security ACL Project
### Relevant Articles
- [Introduction to Spring Security ACL](http://www.baeldung.com/spring-security-acl)

View File

@ -0,0 +1,66 @@
<?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</groupId>
<artifactId>spring-security-acl</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<name>spring-security-acl</name>
<description>Spring Security ACL</description>
<parent>
<artifactId>parent-boot-5</artifactId>
<groupId>com.baeldung</groupId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../parent-boot-5</relativePath>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-acl</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
</dependency>
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache-core</artifactId>
<version>2.6.11</version>
<type>jar</type>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,80 @@
package org.baeldung.acl.config;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.cache.ehcache.EhCacheFactoryBean;
import org.springframework.cache.ehcache.EhCacheManagerFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler;
import org.springframework.security.acls.AclPermissionCacheOptimizer;
import org.springframework.security.acls.AclPermissionEvaluator;
import org.springframework.security.acls.domain.AclAuthorizationStrategy;
import org.springframework.security.acls.domain.AclAuthorizationStrategyImpl;
import org.springframework.security.acls.domain.ConsoleAuditLogger;
import org.springframework.security.acls.domain.DefaultPermissionGrantingStrategy;
import org.springframework.security.acls.domain.EhCacheBasedAclCache;
import org.springframework.security.acls.jdbc.BasicLookupStrategy;
import org.springframework.security.acls.jdbc.JdbcMutableAclService;
import org.springframework.security.acls.jdbc.LookupStrategy;
import org.springframework.security.acls.model.PermissionGrantingStrategy;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
@Configuration
@EnableAutoConfiguration
public class ACLContext {
@Autowired
DataSource dataSource;
@Bean
public EhCacheBasedAclCache aclCache() {
return new EhCacheBasedAclCache(aclEhCacheFactoryBean().getObject(), permissionGrantingStrategy(), aclAuthorizationStrategy());
}
@Bean
public EhCacheFactoryBean aclEhCacheFactoryBean() {
EhCacheFactoryBean ehCacheFactoryBean = new EhCacheFactoryBean();
ehCacheFactoryBean.setCacheManager(aclCacheManager().getObject());
ehCacheFactoryBean.setCacheName("aclCache");
return ehCacheFactoryBean;
}
@Bean
public EhCacheManagerFactoryBean aclCacheManager() {
return new EhCacheManagerFactoryBean();
}
@Bean
public PermissionGrantingStrategy permissionGrantingStrategy() {
return new DefaultPermissionGrantingStrategy(new ConsoleAuditLogger());
}
@Bean
public AclAuthorizationStrategy aclAuthorizationStrategy() {
return new AclAuthorizationStrategyImpl(new SimpleGrantedAuthority("ROLE_ADMIN"));
}
@Bean
public MethodSecurityExpressionHandler defaultMethodSecurityExpressionHandler() {
DefaultMethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
AclPermissionEvaluator permissionEvaluator = new AclPermissionEvaluator(aclService());
expressionHandler.setPermissionEvaluator(permissionEvaluator);
expressionHandler.setPermissionCacheOptimizer(new AclPermissionCacheOptimizer(aclService()));
return expressionHandler;
}
@Bean
public LookupStrategy lookupStrategy() {
return new BasicLookupStrategy(dataSource, aclCache(), aclAuthorizationStrategy(), new ConsoleAuditLogger());
}
@Bean
public JdbcMutableAclService aclService() {
return new JdbcMutableAclService(dataSource, lookupStrategy(), aclCache());
}
}

View File

@ -0,0 +1,21 @@
package org.baeldung.acl.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration;
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class AclMethodSecurityConfiguration extends GlobalMethodSecurityConfiguration {
@Autowired
MethodSecurityExpressionHandler defaultMethodSecurityExpressionHandler;
@Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
return defaultMethodSecurityExpressionHandler;
}
}

View File

@ -0,0 +1,16 @@
package org.baeldung.acl.config;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(basePackages = "org.baeldung.acl.persistence.dao")
@PropertySource("classpath:org.baeldung.acl.datasource.properties")
@EntityScan(basePackages={ "org.baeldung.acl.persistence.entity" })
public class JPAPersistenceConfig {
}

View File

@ -0,0 +1,24 @@
package org.baeldung.acl.persistence.dao;
import java.util.List;
import org.baeldung.acl.persistence.entity.NoticeMessage;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.security.access.prepost.PostAuthorize;
import org.springframework.security.access.prepost.PostFilter;
import org.springframework.security.access.prepost.PreAuthorize;
public interface NoticeMessageRepository extends JpaRepository<NoticeMessage, Long>{
@PostFilter("hasPermission(filterObject, 'READ')")
List<NoticeMessage> findAll();
@PostAuthorize("hasPermission(returnObject, 'READ')")
NoticeMessage findById(Integer id);
@SuppressWarnings("unchecked")
@PreAuthorize("hasPermission(#noticeMessage, 'WRITE')")
NoticeMessage save(@Param("noticeMessage")NoticeMessage noticeMessage);
}

View File

@ -0,0 +1,29 @@
package org.baeldung.acl.persistence.entity;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name="system_message")
public class NoticeMessage {
@Id
@Column
private Integer id;
@Column
private String content;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}

View File

@ -0,0 +1,26 @@
INSERT INTO acl_sid (id, principal, sid) VALUES
(1, 1, 'manager'),
(2, 1, 'hr'),
(3, 0, 'ROLE_EDITOR');
INSERT INTO acl_class (id, class) VALUES
(1, 'org.baeldung.acl.persistence.entity.NoticeMessage');
INSERT INTO system_message(id,content) VALUES
(1,'First Level Message'),
(2,'Second Level Message'),
(3,'Third Level Message');
INSERT INTO acl_object_identity (id, object_id_class, object_id_identity, parent_object, owner_sid, entries_inheriting) VALUES
(1, 1, 1, NULL, 3, 0),
(2, 1, 2, NULL, 3, 0),
(3, 1, 3, NULL, 3, 0);
INSERT INTO acl_entry (id, acl_object_identity, ace_order, sid, mask, granting, audit_success, audit_failure) VALUES
(1, 1, 1, 1, 1, 1, 1, 1),
(2, 1, 2, 1, 2, 1, 1, 1),
(3, 1, 3, 3, 1, 1, 1, 1),
(4, 2, 1, 2, 1, 1, 1, 1),
(5, 2, 2, 3, 1, 1, 1, 1),
(6, 3, 1, 3, 1, 1, 1, 1),
(7, 3, 2, 3, 2, 1, 1, 1);

View File

@ -0,0 +1,58 @@
create table IF NOT EXISTS system_message (id integer not null, content varchar(255), primary key (id));
CREATE TABLE IF NOT EXISTS acl_sid (
id bigint(20) NOT NULL AUTO_INCREMENT,
principal tinyint(1) NOT NULL,
sid varchar(100) NOT NULL,
PRIMARY KEY (id),
UNIQUE KEY unique_uk_1 (sid,principal)
);
CREATE TABLE IF NOT EXISTS acl_class (
id bigint(20) NOT NULL AUTO_INCREMENT,
class varchar(255) NOT NULL,
PRIMARY KEY (id),
UNIQUE KEY unique_uk_2 (class)
);
CREATE TABLE IF NOT EXISTS acl_entry (
id bigint(20) NOT NULL AUTO_INCREMENT,
acl_object_identity bigint(20) NOT NULL,
ace_order int(11) NOT NULL,
sid bigint(20) NOT NULL,
mask int(11) NOT NULL,
granting tinyint(1) NOT NULL,
audit_success tinyint(1) NOT NULL,
audit_failure tinyint(1) NOT NULL,
PRIMARY KEY (id),
UNIQUE KEY unique_uk_4 (acl_object_identity,ace_order)
);
CREATE TABLE IF NOT EXISTS acl_object_identity (
id bigint(20) NOT NULL AUTO_INCREMENT,
object_id_class bigint(20) NOT NULL,
object_id_identity bigint(20) NOT NULL,
parent_object bigint(20) DEFAULT NULL,
owner_sid bigint(20) DEFAULT NULL,
entries_inheriting tinyint(1) NOT NULL,
PRIMARY KEY (id),
UNIQUE KEY unique_uk_3 (object_id_class,object_id_identity)
);
ALTER TABLE acl_entry
ADD FOREIGN KEY (acl_object_identity) REFERENCES acl_object_identity(id);
ALTER TABLE acl_entry
ADD FOREIGN KEY (sid) REFERENCES acl_sid(id);
--
-- Constraints for table acl_object_identity
--
ALTER TABLE acl_object_identity
ADD FOREIGN KEY (parent_object) REFERENCES acl_object_identity (id);
ALTER TABLE acl_object_identity
ADD FOREIGN KEY (object_id_class) REFERENCES acl_class (id);
ALTER TABLE acl_object_identity
ADD FOREIGN KEY (owner_sid) REFERENCES acl_sid (id);

View File

@ -0,0 +1,12 @@
spring.datasource.url=jdbc:h2:mem:testdb;DB_CLOSE_ON_EXIT=FALSE
spring.datasource.username=sa
spring.datasource.password=
spring.datasource.driverClassName=org.h2.Driver
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.H2Dialect
spring.h2.console.path=/myconsole
spring.h2.console.enabled=true
spring.datasource.initialize=true
spring.datasource.schema=classpath:acl-schema.sql
spring.datasource.data=classpath:acl-data.sql

View File

@ -0,0 +1,119 @@
package org.baeldung.acl;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import java.util.List;
import org.baeldung.acl.persistence.dao.NoticeMessageRepository;
import org.baeldung.acl.persistence.entity.NoticeMessage;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.security.test.context.support.WithSecurityContextTestExecutionListener;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
import org.springframework.test.context.support.DirtiesContextTestExecutionListener;
import org.springframework.test.context.transaction.TransactionalTestExecutionListener;
import org.springframework.test.context.web.ServletTestExecutionListener;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
@TestExecutionListeners(listeners={ServletTestExecutionListener.class,
DependencyInjectionTestExecutionListener.class,
DirtiesContextTestExecutionListener.class,
TransactionalTestExecutionListener.class,
WithSecurityContextTestExecutionListener.class})
public class SpringAclTest extends AbstractJUnit4SpringContextTests{
private static Integer FIRST_MESSAGE_ID = 1;
private static Integer SECOND_MESSAGE_ID = 2;
private static Integer THIRD_MESSAGE_ID = 3;
private static String EDITTED_CONTENT = "EDITED";
@Configuration
@ComponentScan("org.baeldung.acl.*")
public static class SpringConfig {
}
@Autowired
NoticeMessageRepository repo;
@Test
@WithMockUser(username="manager")
public void givenUserManager_whenFindAllMessage_thenReturnFirstMessage(){
List<NoticeMessage> details = repo.findAll();
assertNotNull(details);
assertEquals(1,details.size());
assertEquals(FIRST_MESSAGE_ID,details.get(0).getId());
}
@Test
@WithMockUser(username="manager")
public void givenUserManager_whenFind1stMessageByIdAndUpdateItsContent_thenOK(){
NoticeMessage firstMessage = repo.findById(FIRST_MESSAGE_ID);
assertNotNull(firstMessage);
assertEquals(FIRST_MESSAGE_ID,firstMessage.getId());
firstMessage.setContent(EDITTED_CONTENT);
repo.save(firstMessage);
NoticeMessage editedFirstMessage = repo.findById(FIRST_MESSAGE_ID);
assertNotNull(editedFirstMessage);
assertEquals(FIRST_MESSAGE_ID,editedFirstMessage.getId());
assertEquals(EDITTED_CONTENT,editedFirstMessage.getContent());
}
@Test
@WithMockUser(username="hr")
public void givenUsernameHr_whenFindMessageById2_thenOK(){
NoticeMessage secondMessage = repo.findById(SECOND_MESSAGE_ID);
assertNotNull(secondMessage);
assertEquals(SECOND_MESSAGE_ID,secondMessage.getId());
}
@Test(expected=AccessDeniedException.class)
@WithMockUser(username="hr")
public void givenUsernameHr_whenUpdateMessageWithId2_thenFail(){
NoticeMessage secondMessage = new NoticeMessage();
secondMessage.setId(SECOND_MESSAGE_ID);
secondMessage.setContent(EDITTED_CONTENT);
repo.save(secondMessage);
}
@Test
@WithMockUser(roles={"EDITOR"})
public void givenRoleEditor_whenFindAllMessage_thenReturn3Message(){
List<NoticeMessage> details = repo.findAll();
assertNotNull(details);
assertEquals(3,details.size());
}
@Test
@WithMockUser(roles={"EDITOR"})
public void givenRoleEditor_whenUpdateThirdMessage_thenOK(){
NoticeMessage thirdMessage = new NoticeMessage();
thirdMessage.setId(THIRD_MESSAGE_ID);
thirdMessage.setContent(EDITTED_CONTENT);
repo.save(thirdMessage);
}
@Test(expected=AccessDeniedException.class)
@WithMockUser(roles={"EDITOR"})
public void givenRoleEditor_whenFind1stMessageByIdAndUpdateContent_thenFail(){
NoticeMessage firstMessage = repo.findById(FIRST_MESSAGE_ID);
assertNotNull(firstMessage);
assertEquals(FIRST_MESSAGE_ID,firstMessage.getId());
firstMessage.setContent(EDITTED_CONTENT);
repo.save(firstMessage);
}
}

View File

@ -0,0 +1,22 @@
package com.baeldung.junit5.bean;
/**
* Bean that contains utility methods to work with numbers.
*
* @author Donato Rimenti
*
*/
public class NumbersBean {
/**
* Returns true if a number is even, false otherwise.
*
* @param number
* the number to check
* @return true if the argument is even, false otherwise
*/
public boolean isNumberEven(int number) {
return number % 2 == 0;
}
}

View File

@ -0,0 +1,43 @@
package com.baeldung.junit5.bean.test;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import com.baeldung.junit5.bean.NumbersBean;
/**
* Test class for {@link NumbersBean}.
*
* @author Donato Rimenti
*
*/
public class NumbersBeanUnitTest {
/**
* The bean to test.
*/
private NumbersBean bean = new NumbersBean();
/**
* Tests that when an even number is passed to
* {@link NumbersBean#isNumberEven(int)}, true is returned.
*/
@Test
void givenEvenNumber_whenCheckingIsNumberEven_thenTrue() {
boolean result = bean.isNumberEven(8);
Assertions.assertTrue(result);
}
/**
* Tests that when an odd number is passed to
* {@link NumbersBean#isNumberEven(int)}, false is returned.
*/
@Test
void givenOddNumber_whenCheckingIsNumberEven_thenFalse() {
boolean result = bean.isNumberEven(3);
Assertions.assertFalse(result);
}
}

View File

@ -0,0 +1,104 @@
package org.baeldung.bddmockito;
import static org.junit.Assert.fail;
import static org.mockito.BDDMockito.*;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
public class BDDMockitoTest {
PhoneBookService phoneBookService;
PhoneBookRepository phoneBookRepository;
String momContactName = "Mom";
String momPhoneNumber = "01234";
String xContactName = "x";
String tooLongPhoneNumber = "01111111111111";
@Before
public void init() {
phoneBookRepository = Mockito.mock(PhoneBookRepository.class);
phoneBookService = new PhoneBookService(phoneBookRepository);
}
@Test
public void givenValidContactName_whenSearchInPhoneBook_thenRetunPhoneNumber() {
given(phoneBookRepository.contains(momContactName)).willReturn(true);
given(phoneBookRepository.getPhoneNumberByContactName(momContactName))
.will((InvocationOnMock invocation) -> {
if(invocation.getArgument(0).equals(momContactName)) {
return momPhoneNumber;
} else {
return null;
}
});
String phoneNumber = phoneBookService.search(momContactName);
then(phoneBookRepository).should().contains(momContactName);
then(phoneBookRepository).should().getPhoneNumberByContactName(momContactName);
Assert.assertEquals(phoneNumber, momPhoneNumber);
}
@Test
public void givenInvalidContactName_whenSearch_thenRetunNull() {
given(phoneBookRepository.contains(xContactName)).willReturn(false);
String phoneNumber = phoneBookService.search(xContactName);
then(phoneBookRepository).should().contains(xContactName);
then(phoneBookRepository).should(never()).getPhoneNumberByContactName(xContactName);
Assert.assertEquals(phoneNumber, null);
}
@Test
public void givenValidContactNameAndPhoneNumber_whenRegister_thenSucceed() {
given(phoneBookRepository.contains(momContactName)).willReturn(false);
phoneBookService.register(momContactName, momPhoneNumber);
verify(phoneBookRepository).insert(momContactName, momPhoneNumber);
}
@Test
public void givenEmptyPhoneNumber_whenRegister_thenFail() {
given(phoneBookRepository.contains(momContactName)).willReturn(false);
phoneBookService.register(xContactName, "");
then(phoneBookRepository).should(never()).insert(momContactName, momPhoneNumber);
}
@Test
public void givenLongPhoneNumber_whenRegister_thenFail() {
given(phoneBookRepository.contains(xContactName)).willReturn(false);
willThrow(new RuntimeException())
.given(phoneBookRepository).insert(any(String.class), eq(tooLongPhoneNumber));
try {
phoneBookService.register(xContactName, tooLongPhoneNumber);
fail("Should throw exception");
} catch (RuntimeException ex) { }
then(phoneBookRepository).should(never()).insert(momContactName, tooLongPhoneNumber);
}
@Test
public void givenExistentContactName_whenRegister_thenFail() {
given(phoneBookRepository.contains(momContactName))
.willThrow(new RuntimeException("Name already exist"));
try {
phoneBookService.register(momContactName, momPhoneNumber);
fail("Should throw exception");
} catch(Exception ex) { }
then(phoneBookRepository).should(never()).insert(momContactName, momPhoneNumber);
}
}

View File

@ -0,0 +1,26 @@
package org.baeldung.bddmockito;
public interface PhoneBookRepository {
/**
* Insert phone record
* @param name Contact name
* @param phone Phone number
*/
void insert(String name, String phone);
/**
* Search for contact phone number
* @param name Contact name
* @return phone number
*/
String getPhoneNumberByContactName(String name);
/**
* Check if the phonebook contains this contact
* @param name Contact name
* @return true if this contact name exists
*/
boolean contains(String name);
}

View File

@ -0,0 +1,34 @@
package org.baeldung.bddmockito;
public class PhoneBookService {
private PhoneBookRepository phoneBookRepository;
public PhoneBookService(PhoneBookRepository phoneBookRepository) {
this.phoneBookRepository = phoneBookRepository;
}
/**
* Register a contact
* @param name Contact name
* @param phone Phone number
*/
public void register(String name, String phone) {
if(!name.isEmpty() && !phone.isEmpty() && !phoneBookRepository.contains(name)) {
phoneBookRepository.insert(name, phone);
}
}
/**
* Search for a phone number by contact name
* @param name Contact name
* @return Phone number
*/
public String search(String name) {
if(!name.isEmpty() && phoneBookRepository.contains(name)) {
return phoneBookRepository.getPhoneNumberByContactName(name);
}
return null;
}
}

View File

@ -0,0 +1,20 @@
package com.baeldung.vavr.future;
public class Util {
public static String appendData(String initial) {
return initial + "Baeldung!";
}
public static int divideByZero(int num) {
return num / 0;
}
public static String getSubstringMinusOne(String s) {
return s.substring(-1);
}
public static String getSubstringMinusTwo(String s) {
return s.substring(-2);
}
}

View File

@ -0,0 +1,177 @@
package com.baeldung.vavr.future;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import org.junit.Test;
import io.vavr.Tuple;
import io.vavr.Tuple2;
import io.vavr.concurrent.Future;
import io.vavr.control.Option;
import io.vavr.control.Try;
public class FutureTest {
@Test
public void whenChangeExecutorService_thenCorrect() {
String initialValue = "Welcome to ";
Future<String> resultFuture = Future.of(
Executors.newSingleThreadExecutor(),
() -> Util.appendData(initialValue));
String result = resultFuture.get();
assertThat(result).isEqualTo("Welcome to Baeldung!");
}
@Test
public void whenAppendData_thenCorrect1() {
String initialValue = "Welcome to ";
Future<String> resultFuture = Future.of(() -> Util.appendData(initialValue));
String result = resultFuture.get();
assertThat(result).isEqualTo("Welcome to Baeldung!");
}
@Test
public void whenAppendData_thenCorrect2() {
String initialValue = "Welcome to ";
Future<String> resultFuture = Future.of(() -> Util.appendData(initialValue));
resultFuture.await();
Option<Try<String>> futureOption = resultFuture.getValue();
Try<String> futureTry = futureOption.get();
String result = futureTry.get();
assertThat(result).isEqualTo("Welcome to Baeldung!");
}
@Test
public void whenAppendData_thenSuccess() {
String initialValue = "Welcome to ";
Future<String> resultFuture = Future.of(() -> Util.appendData(initialValue))
.onSuccess(finalResult -> System.out.println("Successfully Completed - Result: " + finalResult))
.onFailure(finalResult -> System.out.println("Failed - Result: " + finalResult));
String result = resultFuture.get();
assertThat(result).isEqualTo("Welcome to Baeldung!");
}
@Test
public void whenChainingCallbacks_thenCorrect() {
String initialValue = "Welcome to ";
Future<String> resultFuture = Future.of(() -> Util.appendData(initialValue))
.andThen(finalResult -> System.out.println("Completed - 1: " + finalResult))
.andThen(finalResult -> System.out.println("Completed - 2: " + finalResult));
String result = resultFuture.get();
assertThat(result).isEqualTo("Welcome to Baeldung!");
}
@Test
public void whenCallAwait_thenCorrect() {
String initialValue = "Welcome to ";
Future<String> resultFuture = Future.of(() -> Util.appendData(initialValue));
resultFuture = resultFuture.await();
String result = resultFuture.get();
assertThat(result).isEqualTo("Welcome to Baeldung!");
}
@Test
public void whenDivideByZero_thenGetThrowable1() {
Future<Integer> resultFuture = Future.of(() -> Util.divideByZero(10));
Future<Throwable> throwableFuture = resultFuture.failed();
Throwable throwable = throwableFuture.get();
assertThat(throwable.getMessage()).isEqualTo("/ by zero");
}
@Test
public void whenDivideByZero_thenGetThrowable2() {
Future<Integer> resultFuture = Future.of(() -> Util.divideByZero(10));
resultFuture.await();
Option<Throwable> throwableOption = resultFuture.getCause();
Throwable throwable = throwableOption.get();
assertThat(throwable.getMessage()).isEqualTo("/ by zero");
}
@Test
public void whenDivideByZero_thenCorrect() throws InterruptedException {
Future<Integer> resultFuture = Future.of(() -> Util.divideByZero(10));
resultFuture.await();
assertThat(resultFuture.isCompleted()).isTrue();
assertThat(resultFuture.isSuccess()).isFalse();
assertThat(resultFuture.isFailure()).isTrue();
}
@Test
public void whenAppendData_thenFutureNotEmpty() {
String initialValue = "Welcome to ";
Future<String> resultFuture = Future.of(() -> Util.appendData(initialValue));
resultFuture.await();
assertThat(resultFuture.isEmpty()).isFalse();
}
@Test
public void whenCallZip_thenCorrect() {
Future<Tuple2<String, Integer>> future = Future.of(() -> "John")
.zip(Future.of(() -> new Integer(5)));
future.await();
assertThat(future.get()).isEqualTo(Tuple.of("John", new Integer(5)));
}
@Test
public void whenConvertToCompletableFuture_thenCorrect() throws InterruptedException, ExecutionException {
String initialValue = "Welcome to ";
Future<String> resultFuture = Future.of(() -> Util.appendData(initialValue));
CompletableFuture<String> convertedFuture = resultFuture.toCompletableFuture();
assertThat(convertedFuture.get()).isEqualTo("Welcome to Baeldung!");
}
@Test
public void whenCallMap_thenCorrect() {
Future<String> futureResult = Future.of(() -> new StringBuilder("from Baeldung"))
.map(a -> "Hello " + a);
futureResult.await();
assertThat(futureResult.get()).isEqualTo("Hello from Baeldung");
}
@Test
public void whenFutureFails_thenGetErrorMessage() {
Future<String> resultFuture = Future.of(() -> Util.getSubstringMinusOne("Hello"));
Future<String> errorMessageFuture = resultFuture.recover(Throwable::getMessage);
String errorMessage = errorMessageFuture.get();
assertThat(errorMessage).isEqualTo("String index out of range: -1");
}
@Test
public void whenFutureFails_thenGetAnotherFuture() {
Future<String> resultFuture = Future.of(() -> Util.getSubstringMinusOne("Hello"));
Future<String> errorMessageFuture = resultFuture.recoverWith(a -> Future.of(a::getMessage));
String errorMessage = errorMessageFuture.get();
assertThat(errorMessage).isEqualTo("String index out of range: -1");
}
@Test
public void whenBothFuturesFail_thenGetErrorMessage() {
Future<String> future1 = Future.of(() -> Util.getSubstringMinusOne("Hello"));
Future<String> future2 = Future.of(() -> Util.getSubstringMinusTwo("Hello"));
Future<String> errorMessageFuture = future1.fallbackTo(future2);
Future<Throwable> errorMessage = errorMessageFuture.failed();
assertThat(
errorMessage.get().getMessage())
.isEqualTo("String index out of range: -1");
}
}

View File

@ -1,289 +0,0 @@
package com.baeldung.vavr.future;
import static io.vavr.API.$;
import static io.vavr.API.Case;
import static io.vavr.API.Match;
import static io.vavr.Predicates.exists;
import static io.vavr.Predicates.forAll;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.util.concurrent.CancellationException;
import java.util.function.Consumer;
import java.util.function.Predicate;
import org.junit.Test;
import org.mockito.Mockito;
import org.mockito.internal.verification.VerificationModeFactory;
import org.mockito.verification.Timeout;
import io.vavr.Tuple;
import io.vavr.Tuple2;
import io.vavr.collection.List;
import io.vavr.concurrent.Future;
import io.vavr.control.Try;
public class FutureUnitTest {
private final String SUCCESS = "Success";
private final String FAILURE = "Failure";
@Test
public void givenFunctionReturnInteger_WhenCallWithFuture_ShouldReturnFunctionValue() {
Future<Integer> future = Future.of(() -> 1);
assertEquals(1, future.get().intValue());
}
@Test
public void givenFunctionGetRemoteHttpResourceAsString_WhenCallSuccessWithFuture_ShouldReturnContentValueAsString() {
String url = "http://resource";
String content = "Content from " + url;
Future<String> future = Future.of(() -> getResource(url));
assertEquals(content, future.get());
}
@Test
public void givenFunctionThrowException_WhenCallWithFuture_ShouldReturnFailure() {
Future<String> future = Future.of(() -> getResourceThrowException(""));
future.await();
assertTrue(future.isFailure());
}
@Test
public void givenAFutureReturnZero_WhenCheckFutureWithExistEvenValue_ShouldReturnRight() {
Future<Integer> future = Future.of(() -> 2);
boolean result = future.exists(i -> i % 2 == 0);
assertTrue(result);
}
@Test
public void givenFunction_WhenCallWithFutureAndRegisterConsumerForSuccess_ShouldCallConsumerToStoreValue() {
Future<Integer> future = Future.of(() -> 1);
MockConsumer consumer = Mockito.mock(MockConsumer.class);
future.onSuccess(consumer);
Mockito.verify(consumer, new Timeout(1000, VerificationModeFactory.times(1))).accept(1);
}
@Test
public void givenFunctionThrowException_WhenCallWithFutureAndRegisterConsumerForFailer_ShouldCallConsumerToStoreException() {
Future<String> future = Future.of(() -> getResourceThrowException(""));
MockThrowableConsumer consumer = Mockito.mock(MockThrowableConsumer.class);
future.onFailure(consumer);
Mockito.verify(consumer, new Timeout(1000, VerificationModeFactory.times(1))).accept(Mockito.any());
}
@Test
public void givenAFuture_WhenAddAndThenConsumer_ShouldCallConsumerWithResultOfFutureAction() {
MockTryConsumer consumer1 = Mockito.mock(MockTryConsumer.class);
MockTryConsumer consumer2 = Mockito.mock(MockTryConsumer.class);
Future<Integer> future = Future.of(() -> 1);
Future<Integer> andThenFuture = future.andThen(consumer1).andThen(consumer2);
andThenFuture.await();
Mockito.verify(consumer1, VerificationModeFactory.times(1)).accept(Try.success(1));
Mockito.verify(consumer2, VerificationModeFactory.times(1)).accept(Try.success(1));
}
@Test
public void givenAFailureFuture_WhenCallOrElseFunction_ShouldReturnNewFuture() {
Future<Integer> future = Future.failed(new RuntimeException());
Future<Integer> future2 = future.orElse(Future.of(() -> 2));
assertEquals(2, future2.get().intValue());
}
@Test(expected = CancellationException.class)
public void givenAFuture_WhenCallCancel_ShouldReturnCancellationException() {
long waitTime = 1000;
Future<Integer> future = Future.of(() -> {
Thread.sleep(waitTime);
return 1;
});
future.cancel();
future.await();
future.get();
}
@Test
public void givenAFuture_WhenCallFallBackWithSuccessFuture_ShouldReturnFutureResult() {
String expectedResult = "take this";
Future<String> future = Future.of(() -> expectedResult);
Future<String> secondFuture = Future.of(() -> "take that");
Future<String> futureResult = future.fallbackTo(secondFuture);
futureResult.await();
assertEquals(expectedResult, futureResult.get());
}
@Test
public void givenAFuture_WhenCallFallBackWithFailureFuture_ShouldReturnValueOfFallBackFuture() {
String expectedResult = "take that";
Future<String> future = Future.failed(new RuntimeException());
Future<String> fallbackFuture = Future.of(() -> expectedResult);
Future<String> futureResult = future.fallbackTo(fallbackFuture);
assertEquals(expectedResult, futureResult.get());
}
@Test
public void givenAFuture_WhenTransformByAddingOne_ShouldReturn() {
Future<Object> future = Future.of(() -> 1).transformValue(f -> Try.of(() -> "Hello: " + f.get()));
assertEquals("Hello: 1", future.get());
}
@Test
public void givenAFutureOfInt_WhenMapToString_ShouldCombineAndReturn() {
Future<String> future = Future.of(()->1).map(i -> "Hello: " + i);
assertEquals("Hello: 1", future.get());
}
@Test
public void givenAFutureOfInt_WhenFlatMapToString_ShouldCombineAndReturn() {
Future<Object> futureMap = Future.of(() -> 1).flatMap((i) -> Future.of(() -> "Hello: " + i));
assertEquals("Hello: 1", futureMap.get());
}
@Test
public void givenAFutureOf2String_WhenZip_ShouldReturnTupleOf2String() {
Future<Tuple2<String, String>> future = Future.of(() -> "hello").zip(Future.of(() -> "world"));
assertEquals(Tuple.of("hello", "world"), future.get());
}
@Test
public void givenGetResourceWithFuture_WhenWaitAndMatchWithPredicate_ShouldReturnSuccess() {
String url = "http://resource";
Future<String> future = Future.of(() -> getResource(url));
future.await();
String s = Match(future).of(
Case($(future0 -> future0.isSuccess()), SUCCESS),
Case($(), FAILURE));
assertEquals(SUCCESS, s);
}
@Test
public void givenAFailedFuture_WhenWaitAndMatchWithPredicateCheckSuccess_ShouldReturnFailed() {
Future<Integer> future = Future.failed(new RuntimeException());
future.await();
String s = Match(future).of(
Case($(future0 -> future0.isSuccess()), SUCCESS),
Case($(), FAILURE));
assertEquals(FAILURE, s);
}
@Test
public void givenAFuture_WhenMatchWithFuturePredicate_ShouldReturnSuccess() {
Future<Integer> future = Future.of(() -> {
Thread.sleep(10);
return 1;
});
Predicate<Future<Integer>> predicate = f -> f.exists(i -> i % 2 == 1);
String s = Match(future).of(
Case($(predicate), "Even"),
Case($(), "Odd"));
assertEquals("Even", s);
}
@Test
public void givenAListOfFutureReturnFist3Integers_WhenMatchWithExistEvenNumberPredicate_ShouldReturnSuccess() {
List<Future<Integer>> futures = getFutureOfFirst3Number();
Predicate<Future<Integer>> predicate0 = future -> future.exists(i -> i % 2 == 0);
String s = Match(futures).of(
Case($(exists(predicate0)), "Even"),
Case($(), "Odd"));
assertEquals("Even", s);
}
@Test
public void givenAListOfFutureReturnFist3Integers_WhenMatchWithForAllNumberBiggerThanZeroPredicate_ShouldReturnSuccess() {
List<Future<Integer>> futures = getFutureOfFirst3Number();
Predicate<Future<Integer>> predicate0 = future -> future.exists(i -> i > 0);
String s = Match(futures).of(
Case($(forAll(predicate0)), "Positive numbers"),
Case($(), "None"));
assertEquals("Positive numbers", s);
}
@Test
public void givenAListOfFutureReturnFist3Integers_WhenMatchWithForAllNumberSmallerThanZeroPredicate_ShouldReturnFailed() {
List<Future<Integer>> futures = getFutureOfFirst3Number();
Predicate<Future<Integer>> predicate0 = future -> future.exists(i -> i < 0);
String s = Match(futures).of(
Case($(forAll(predicate0)), "Negative numbers"),
Case($(), "None"));
assertEquals("None", s);
}
private String getResource(String url) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return "Content from " + url;
}
private String getResourceThrowException(String url) {
throw new RuntimeException("Exception when get resource " + url);
}
private List<Future<Integer>> getFutureOfFirst3Number() {
List<Future<Integer>> futures = List.of(Future.of(() -> 1), Future.of(() -> 2), Future.of(() -> 3));
return futures;
}
private static void checkOnSuccessFunction() {
Future<Integer> future = Future.of(() -> 1);
future.onSuccess(i -> System.out.println("Future finish with result: " + i));
}
private static void checkOnFailureFunction() {
Future<Integer> future = Future.of(() -> {throw new RuntimeException("Failed");});
future.onFailure(t -> System.out.println("Future failures with exception: " + t));
}
private static void runAndThenConsumer() {
Future<Integer> future = Future.of(() -> 1);
future.andThen(i -> System.out.println("Do side-effect action 1 with input: " + i.get())).
andThen((i) -> System.out.println("Do side-effect action 2 with input: " + i.get()));
}
public static void main(String[] args) throws InterruptedException {
checkOnSuccessFunction();
checkOnFailureFunction();
runAndThenConsumer();
Thread.sleep(1000);
}
}
class MockConsumer implements Consumer<Integer> {
@Override
public void accept(Integer t) {
}
}
class MockTryConsumer implements Consumer<Try<Integer>> {
@Override
public void accept(Try<Integer> t) {
}
}
class MockThrowableConsumer implements Consumer<Throwable> {
@Override
public void accept(Throwable t) {
}
}

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<XMLTutorials>
<tutorial tutId="01" type="xml">
<title>XML with Dom4J</title>
<description>XML handling with Dom4J</description>
<date>14/06/2016</date>
<author>Dom4J tech writer</author>
</tutorial>
</XMLTutorials>

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<tutorials>
<tutorial tutId="01" type="XML">
<author>Jaxb author</author>
<date>04/02/2015</date>
<description>XML Binding with Jaxb</description>
<title>XML with Jaxb</title>
</tutorial>
</tutorials>