Merge branch 'master' of github.com:eugenp/tutorials
This commit is contained in:
commit
f52e9e3e3a
@ -3,7 +3,7 @@
|
||||
This module contains articles about Apache CXF
|
||||
|
||||
## Relevant Articles:
|
||||
- [Introduction to Apache CXF Aegis Data Binding](https://www.baeldung.com/aegis-data-binding-in-apache-cxf)
|
||||
|
||||
- [Apache CXF Support for RESTful Web Services](https://www.baeldung.com/apache-cxf-rest-api)
|
||||
- [A Guide to Apache CXF with Spring](https://www.baeldung.com/apache-cxf-with-spring)
|
||||
- [Introduction to Apache CXF](https://www.baeldung.com/introduction-to-apache-cxf)
|
||||
|
3
apache-cxf/cxf-aegis/README.md
Normal file
3
apache-cxf/cxf-aegis/README.md
Normal file
@ -0,0 +1,3 @@
|
||||
### Relevant Articles:
|
||||
|
||||
- [Introduction to Apache CXF Aegis Data Binding](https://www.baeldung.com/aegis-data-binding-in-apache-cxf)
|
@ -0,0 +1,83 @@
|
||||
package com.baeldung.exchanger;
|
||||
|
||||
import java.util.Queue;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.concurrent.Exchanger;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import org.junit.Test;
|
||||
|
||||
import static java.util.concurrent.CompletableFuture.runAsync;
|
||||
|
||||
|
||||
|
||||
public class ExchangerPipeLineManualTest {
|
||||
|
||||
private static final int BUFFER_SIZE = 100;
|
||||
|
||||
@Test
|
||||
public void givenData_whenPassedThrough_thenCorrect() throws InterruptedException, ExecutionException {
|
||||
|
||||
Exchanger<Queue<String>> readerExchanger = new Exchanger<>();
|
||||
Exchanger<Queue<String>> writerExchanger = new Exchanger<>();
|
||||
int counter = 0;
|
||||
|
||||
Runnable reader = () -> {
|
||||
Queue<String> readerBuffer = new ConcurrentLinkedQueue<>();
|
||||
while (true) {
|
||||
readerBuffer.add(UUID.randomUUID().toString());
|
||||
if (readerBuffer.size() >= BUFFER_SIZE) {
|
||||
try {
|
||||
readerBuffer = readerExchanger.exchange(readerBuffer);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Runnable processor = () -> {
|
||||
Queue<String> processorBuffer = new ConcurrentLinkedQueue<>();
|
||||
Queue<String> writterBuffer = new ConcurrentLinkedQueue<>();
|
||||
try {
|
||||
processorBuffer = readerExchanger.exchange(processorBuffer);
|
||||
while (true) {
|
||||
writterBuffer.add(processorBuffer.poll());
|
||||
if (processorBuffer.isEmpty()) {
|
||||
try {
|
||||
processorBuffer = readerExchanger.exchange(processorBuffer);
|
||||
writterBuffer = writerExchanger.exchange(writterBuffer);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
};
|
||||
|
||||
Runnable writer = () -> {
|
||||
Queue<String> writterBuffer = new ConcurrentLinkedQueue<>();
|
||||
try {
|
||||
writterBuffer = writerExchanger.exchange(writterBuffer);
|
||||
while (true) {
|
||||
System.out.println(writterBuffer.poll());
|
||||
if (writterBuffer.isEmpty()) {
|
||||
writterBuffer = writerExchanger.exchange(writterBuffer);
|
||||
}
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
};
|
||||
|
||||
CompletableFuture.allOf(runAsync(reader), runAsync(processor), runAsync(writer)).get();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
package com.baeldung.exchanger;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.Exchanger;
|
||||
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import org.junit.Test;
|
||||
|
||||
import static java.util.concurrent.CompletableFuture.runAsync;
|
||||
|
||||
public class ExchangerUnitTest {
|
||||
|
||||
|
||||
@Test
|
||||
public void givenThreads_whenMessageExchanged_thenCorrect() {
|
||||
Exchanger<String> exchanger = new Exchanger<>();
|
||||
|
||||
Runnable taskA = () -> {
|
||||
try {
|
||||
String message = exchanger.exchange("from A");
|
||||
assertEquals("from B", message);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
};
|
||||
|
||||
Runnable taskB = () -> {
|
||||
try {
|
||||
String message = exchanger.exchange("from B");
|
||||
assertEquals("from A", message);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
};
|
||||
|
||||
CompletableFuture.allOf(runAsync(taskA), runAsync(taskB)).join();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenThread_WhenExchangedMessage_thenCorrect() throws InterruptedException, ExecutionException {
|
||||
Exchanger<String> exchanger = new Exchanger<>();
|
||||
|
||||
Runnable runner = () -> {
|
||||
try {
|
||||
String message = exchanger.exchange("from runner");
|
||||
assertEquals("to runner", message);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
};
|
||||
|
||||
CompletableFuture<Void> result = CompletableFuture.runAsync(runner);
|
||||
String msg = exchanger.exchange("to runner");
|
||||
assertEquals("from runner", msg);
|
||||
result.join();
|
||||
}
|
||||
|
||||
}
|
@ -11,13 +11,26 @@ import org.junit.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.*;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.io.Reader;
|
||||
import java.io.StringReader;
|
||||
import java.io.StringWriter;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.util.Scanner;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
@ -46,6 +59,18 @@ public class JavaInputStreamToXUnitTest {
|
||||
assertEquals(textBuilder.toString(), originalString);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenUsingJava8_whenConvertingAnInputStreamToAString_thenCorrect() {
|
||||
final String originalString = randomAlphabetic(DEFAULT_SIZE);
|
||||
final InputStream inputStream = new ByteArrayInputStream(originalString.getBytes());
|
||||
|
||||
final String text = new BufferedReader(new InputStreamReader(inputStream, Charset.forName(StandardCharsets.UTF_8.name())))
|
||||
.lines()
|
||||
.collect(Collectors.joining("\n"));
|
||||
|
||||
assertThat(text, equalTo(originalString));
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void givenUsingJava7_whenConvertingAnInputStreamToAString_thenCorrect() throws IOException {
|
||||
final String originalString = randomAlphabetic(DEFAULT_SIZE);
|
||||
|
@ -0,0 +1,86 @@
|
||||
package com.baeldung.ifelseexpression
|
||||
|
||||
fun ifStatementUsage(): String {
|
||||
val number = 15
|
||||
|
||||
if (number > 0) {
|
||||
return "Positive number"
|
||||
}
|
||||
return "Positive number not found"
|
||||
}
|
||||
|
||||
fun ifElseStatementUsage(): String {
|
||||
val number = -50
|
||||
|
||||
if (number > 0) {
|
||||
return "Positive number"
|
||||
} else {
|
||||
return "Negative number"
|
||||
}
|
||||
}
|
||||
|
||||
fun ifElseExpressionUsage(): String {
|
||||
val number = -50
|
||||
|
||||
val result = if (number > 0) {
|
||||
"Positive number"
|
||||
} else {
|
||||
"Negative number"
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
fun ifElseExpressionSingleLineUsage(): String {
|
||||
val number = -50
|
||||
val result = if (number > 0) "Positive number" else "Negative number"
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
fun ifElseMultipleExpressionUsage(): Int {
|
||||
val x = 24
|
||||
val y = 73
|
||||
|
||||
val result = if (x > y) {
|
||||
println("$x is greater than $y")
|
||||
x
|
||||
} else {
|
||||
println("$x is less than or equal to $y")
|
||||
y
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
fun ifElseLadderExpressionUsage(): String {
|
||||
val number = 60
|
||||
|
||||
val result = if (number < 0) {
|
||||
"Negative number"
|
||||
} else if (number in 0..9) {
|
||||
"Single digit number"
|
||||
} else if (number in 10..99) {
|
||||
"Double digit number"
|
||||
} else {
|
||||
"Number has more digits"
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
fun ifElseNestedExpressionUsage(): Int {
|
||||
val x = 37
|
||||
val y = 89
|
||||
val z = 6
|
||||
|
||||
val result = if (x > y) {
|
||||
if (x > z)
|
||||
x
|
||||
else
|
||||
z
|
||||
} else {
|
||||
if (y > z)
|
||||
y
|
||||
else
|
||||
z
|
||||
}
|
||||
return result
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
package com.baeldung.ifelseexpression
|
||||
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Assertions.assertNotEquals
|
||||
|
||||
class IfElseExpressionExampleTest {
|
||||
|
||||
@Test
|
||||
fun givenNumber_whenIfStatementCalled_thenReturnsString() {
|
||||
assertEquals("Positive number", ifStatementUsage())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun givenNumber_whenIfElseStatementCalled_thenReturnsString() {
|
||||
assertEquals("Negative number", ifElseStatementUsage())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun givenNumber_whenIfElseExpressionCalled_thenReturnsString() {
|
||||
assertEquals("Negative number", ifElseExpressionUsage())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun givenNumber_whenIfElseExpressionSingleLineCalled_thenReturnsString() {
|
||||
assertEquals("Negative number", ifElseExpressionSingleLineUsage())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun givenNumber_whenIfElseMultipleExpressionCalled_thenReturnsNumber() {
|
||||
assertEquals(73, ifElseMultipleExpressionUsage())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun givenNumber_whenIfElseLadderExpressionCalled_thenReturnsString() {
|
||||
assertEquals("Double digit number", ifElseLadderExpressionUsage())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun givenNumber_whenIfElseNestedExpressionCalled_thenReturnsNumber() {
|
||||
assertEquals(89, ifElseNestedExpressionUsage())
|
||||
}
|
||||
}
|
@ -88,7 +88,7 @@ public class CollectionToArrayListUnitTest {
|
||||
Iterator<Foo> iterA = a.iterator();
|
||||
Iterator<Foo> iterB = b.iterator();
|
||||
while (iterA.hasNext()) {
|
||||
// use '==' to test instance identity
|
||||
// test instance identity
|
||||
assertSame("Foo instances differ!", iterA.next(), iterB.next());
|
||||
}
|
||||
}
|
||||
|
41
patterns/solid/src/main/java/com/baeldung/o/Addition.java
Normal file
41
patterns/solid/src/main/java/com/baeldung/o/Addition.java
Normal file
@ -0,0 +1,41 @@
|
||||
package com.baeldung.o;
|
||||
|
||||
public class Addition implements CalculatorOperation {
|
||||
private double number1;
|
||||
private double number2;
|
||||
private double result = 0.0;
|
||||
|
||||
public Addition(double number1, double number2) {
|
||||
this.number1 = number1;
|
||||
this.number2 = number2;
|
||||
}
|
||||
|
||||
public double getNumber1() {
|
||||
return number1;
|
||||
}
|
||||
|
||||
public void setNumber1(double number1) {
|
||||
this.number1 = number1;
|
||||
}
|
||||
|
||||
public double getNumber2() {
|
||||
return number2;
|
||||
}
|
||||
|
||||
public void setNumber2(double number2) {
|
||||
this.number2 = number2;
|
||||
}
|
||||
|
||||
public double getResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
public void setResult(double result) {
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void perform() {
|
||||
result = number1 + number2;
|
||||
}
|
||||
}
|
14
patterns/solid/src/main/java/com/baeldung/o/Calculator.java
Normal file
14
patterns/solid/src/main/java/com/baeldung/o/Calculator.java
Normal file
@ -0,0 +1,14 @@
|
||||
package com.baeldung.o;
|
||||
|
||||
import java.security.InvalidParameterException;
|
||||
|
||||
public class Calculator {
|
||||
|
||||
public void calculate(CalculatorOperation operation) {
|
||||
if (operation == null) {
|
||||
throw new InvalidParameterException("Can not perform operation");
|
||||
}
|
||||
|
||||
operation.perform();
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package com.baeldung.o;
|
||||
|
||||
public interface CalculatorOperation {
|
||||
|
||||
void perform();
|
||||
|
||||
}
|
43
patterns/solid/src/main/java/com/baeldung/o/Division.java
Normal file
43
patterns/solid/src/main/java/com/baeldung/o/Division.java
Normal file
@ -0,0 +1,43 @@
|
||||
package com.baeldung.o;
|
||||
|
||||
public class Division implements CalculatorOperation {
|
||||
private double number1;
|
||||
private double number2;
|
||||
private double result = 0.0;
|
||||
|
||||
public Division(double number1, double number2) {
|
||||
this.number1 = number1;
|
||||
this.number2 = number2;
|
||||
}
|
||||
|
||||
public double getNumber1() {
|
||||
return number1;
|
||||
}
|
||||
|
||||
public void setNumber1(double number1) {
|
||||
this.number1 = number1;
|
||||
}
|
||||
|
||||
public double getNumber2() {
|
||||
return number2;
|
||||
}
|
||||
|
||||
public void setNumber2(double number2) {
|
||||
this.number2 = number2;
|
||||
}
|
||||
|
||||
public double getResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
public void setResult(double result) {
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void perform() {
|
||||
if (number2 != 0) {
|
||||
result = number1 / number2;
|
||||
}
|
||||
}
|
||||
}
|
41
patterns/solid/src/main/java/com/baeldung/o/Subtraction.java
Normal file
41
patterns/solid/src/main/java/com/baeldung/o/Subtraction.java
Normal file
@ -0,0 +1,41 @@
|
||||
package com.baeldung.o;
|
||||
|
||||
public class Subtraction implements CalculatorOperation {
|
||||
private double number1;
|
||||
private double number2;
|
||||
private double result = 0.0;
|
||||
|
||||
public Subtraction(double number1, double number2) {
|
||||
this.number1 = number1;
|
||||
this.number2 = number2;
|
||||
}
|
||||
|
||||
public double getNumber1() {
|
||||
return number1;
|
||||
}
|
||||
|
||||
public void setNumber1(double number1) {
|
||||
this.number1 = number1;
|
||||
}
|
||||
|
||||
public double getNumber2() {
|
||||
return number2;
|
||||
}
|
||||
|
||||
public void setNumber2(double number2) {
|
||||
this.number2 = number2;
|
||||
}
|
||||
|
||||
public double getResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
public void setResult(double result) {
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void perform() {
|
||||
result = number1 - number2;
|
||||
}
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
package com.baeldung.o;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class CalculatorUnitTest {
|
||||
|
||||
private static final double NUMBER_1 = 10.0;
|
||||
private static final double NUMBER_2 = 20.0;
|
||||
private static final double SUM = 30.0;
|
||||
private static final double SUBTRACTION_RESULT = 10.0;
|
||||
private static final double DIVISION_RESULT = 2.0;
|
||||
|
||||
private Calculator calculator;
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
calculator = new Calculator();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenAddTwoNumber_returnSum() {
|
||||
Addition addition = new Addition(NUMBER_1, NUMBER_2);
|
||||
calculator.calculate(addition);
|
||||
assertEquals(SUM, addition.getResult(), 0.0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenSutractTwoNumber_returnCorrectResult() {
|
||||
Subtraction subtraction = new Subtraction(NUMBER_2, NUMBER_1);
|
||||
calculator.calculate(subtraction);
|
||||
assertEquals(SUBTRACTION_RESULT, subtraction.getResult(), 0.0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenDivideTwoNumber_returnCorrectResult() {
|
||||
Division division = new Division(NUMBER_2, NUMBER_1);
|
||||
calculator.calculate(division);
|
||||
assertEquals(DIVISION_RESULT, division.getResult(), 0.0);
|
||||
}
|
||||
|
||||
}
|
@ -87,19 +87,6 @@
|
||||
</build>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>spring-snapshots</id>
|
||||
<name>Spring Snapshots</name>
|
||||
<url>https://repo.spring.io/snapshot</url>
|
||||
<snapshots>
|
||||
<enabled>true</enabled>
|
||||
</snapshots>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>spring-milestones</id>
|
||||
<name>Spring Milestones</name>
|
||||
<url>https://repo.spring.io/milestone</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>jcenter-snapshots</id>
|
||||
<name>jcenter</name>
|
||||
@ -107,27 +94,12 @@
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<pluginRepositories>
|
||||
<pluginRepository>
|
||||
<id>spring-snapshots</id>
|
||||
<name>Spring Snapshots</name>
|
||||
<url>https://repo.spring.io/snapshot</url>
|
||||
<snapshots>
|
||||
<enabled>true</enabled>
|
||||
</snapshots>
|
||||
</pluginRepository>
|
||||
<pluginRepository>
|
||||
<id>spring-milestones</id>
|
||||
<name>Spring Milestones</name>
|
||||
<url>https://repo.spring.io/milestone</url>
|
||||
</pluginRepository>
|
||||
</pluginRepositories>
|
||||
|
||||
<properties>
|
||||
<spring.fox.version>3.0.0-SNAPSHOT</spring.fox.version>
|
||||
<start-class>com.baeldung.swagger2boot.SpringBootSwaggerApplication</start-class>
|
||||
<!-- <start-class>com.baeldung.springbootmvc.SpringBootMvcFnApplication</start-class> -->
|
||||
<spring-boot.version>2.2.0.BUILD-SNAPSHOT</spring-boot.version>
|
||||
<spring-boot.version>2.2.6.RELEASE</spring-boot.version>
|
||||
<xstream.version>1.4.11.1</xstream.version>
|
||||
</properties>
|
||||
|
||||
|
5
spring-boot-modules/spring-boot-properties-2/README.md
Normal file
5
spring-boot-modules/spring-boot-properties-2/README.md
Normal file
@ -0,0 +1,5 @@
|
||||
## Spring Boot Properties
|
||||
|
||||
This module contains articles about Properties in Spring Boot.
|
||||
|
||||
### Relevant Articles:
|
25
spring-boot-modules/spring-boot-properties-2/pom.xml
Normal file
25
spring-boot-modules/spring-boot-properties-2/pom.xml
Normal file
@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>spring-boot-properties-2</artifactId>
|
||||
<name>spring-boot-properties-2</name>
|
||||
<packaging>jar</packaging>
|
||||
<description>Spring Boot Properties Module</description>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
|
||||
<parent>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>parent-boot-2</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<relativePath>../../parent-boot-2</relativePath>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
@ -0,0 +1,22 @@
|
||||
package com.baeldung.properties.yaml;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.CommandLineRunner;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class YamlApplication implements CommandLineRunner {
|
||||
|
||||
@Autowired
|
||||
private YamlFooProperties yamlFooProperties;
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(YamlApplication.class, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(String... args) throws Exception {
|
||||
System.out.println("YAML Properties " + yamlFooProperties);
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
package com.baeldung.properties.yaml;
|
||||
|
||||
import com.baeldung.properties.yaml.factory.YamlPropertySourceFactory;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.PropertySource;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Configuration
|
||||
@ConfigurationProperties(prefix = "yaml")
|
||||
@PropertySource(value = "classpath:foo.yml", factory = YamlPropertySourceFactory.class)
|
||||
public class YamlFooProperties {
|
||||
|
||||
private String name;
|
||||
|
||||
private List<String> aliases;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public List<String> getAliases() {
|
||||
return aliases;
|
||||
}
|
||||
|
||||
public void setAliases(List<String> aliases) {
|
||||
this.aliases = aliases;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "YamlFooProperties{" +
|
||||
"name='" + name + '\'' +
|
||||
", aliases=" + aliases +
|
||||
'}';
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
package com.baeldung.properties.yaml.factory;
|
||||
|
||||
import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
|
||||
import org.springframework.core.env.PropertiesPropertySource;
|
||||
import org.springframework.core.env.PropertySource;
|
||||
import org.springframework.core.io.support.EncodedResource;
|
||||
import org.springframework.core.io.support.PropertySourceFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Properties;
|
||||
|
||||
public class YamlPropertySourceFactory implements PropertySourceFactory {
|
||||
|
||||
@Override
|
||||
public PropertySource<?> createPropertySource(String name, EncodedResource encodedResource) throws IOException {
|
||||
YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
|
||||
factory.setResources(encodedResource.getResource());
|
||||
|
||||
Properties properties = factory.getObject();
|
||||
|
||||
return new PropertiesPropertySource(encodedResource.getResource().getFilename(), properties);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
yaml:
|
||||
name: foo
|
||||
aliases:
|
||||
- abc
|
||||
- xyz
|
@ -0,0 +1,23 @@
|
||||
package com.baeldung.properties.yaml;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest
|
||||
public class YamlFooPropertiesIntegrationTest {
|
||||
|
||||
@Autowired
|
||||
private YamlFooProperties yamlFooProperties;
|
||||
|
||||
@Test
|
||||
public void whenFactoryProvidedThenYamlPropertiesInjected() {
|
||||
assertThat(yamlFooProperties.getName()).isEqualTo("foo");
|
||||
assertThat(yamlFooProperties.getAliases()).containsExactly("abc", "xyz");
|
||||
}
|
||||
}
|
@ -7,7 +7,7 @@ import org.springframework.context.annotation.ComponentScan;
|
||||
import com.baeldung.configurationproperties.ConfigProperties;
|
||||
|
||||
@SpringBootApplication
|
||||
@ComponentScan(basePackageClasses = { ConfigProperties.class, JsonProperties.class, CustomJsonProperties.class, Database.class })
|
||||
@ComponentScan(basePackageClasses = { ConfigProperties.class, JsonProperties.class, CustomJsonProperties.class})
|
||||
public class ConfigPropertiesDemoApplication {
|
||||
public static void main(String[] args) {
|
||||
new SpringApplicationBuilder(ConfigPropertiesDemoApplication.class).initializers(new JsonPropertyContextInitializer())
|
||||
|
@ -1,33 +0,0 @@
|
||||
package com.baeldung.properties;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
@ConfigurationProperties(prefix = "database")
|
||||
public class Database {
|
||||
|
||||
private String url;
|
||||
private String username;
|
||||
private String password;
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
public void setUrl(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
}
|
@ -14,8 +14,4 @@
|
||||
<constructor-arg value="${key.something}"/>
|
||||
</bean>
|
||||
|
||||
<bean id="dataSource" class="com.baeldung.configurationproperties.Database">
|
||||
<property name="url" value="${jdbc.url}" />
|
||||
</bean>
|
||||
|
||||
</beans>
|
@ -1,4 +1,3 @@
|
||||
|
||||
jdbc.url=jdbc:postgresql:/localhost:5432
|
||||
database.username=foo
|
||||
database.password=bar
|
||||
|
@ -1,5 +1,6 @@
|
||||
database:
|
||||
url: jdbc:postresql:/localhost:5432/instance
|
||||
jdbc:
|
||||
url: jdbc:postresql:/localhost:5432
|
||||
username: foo
|
||||
password: bar
|
||||
secret: foo
|
@ -14,17 +14,13 @@ import com.baeldung.properties.AdditionalProperties;
|
||||
import com.baeldung.properties.ConfigPropertiesDemoApplication;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(classes = {ConfigPropertiesDemoApplication.class, DatabaseConfigPropertiesApp.class})
|
||||
@TestPropertySource(locations = {"classpath:configprops-test.properties", "classpath:database-test.properties"})
|
||||
@SpringBootTest(classes = {ConfigPropertiesDemoApplication.class})
|
||||
@TestPropertySource(locations = {"classpath:configprops-test.properties"})
|
||||
public class ConfigPropertiesIntegrationTest {
|
||||
|
||||
@Autowired
|
||||
private ConfigProperties properties;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("dataSource")
|
||||
private Database databaseProperties;
|
||||
|
||||
@Autowired
|
||||
private AdditionalProperties additionalProperties;
|
||||
|
||||
@ -59,10 +55,4 @@ public class ConfigPropertiesIntegrationTest {
|
||||
Assert.assertTrue(additionalProperties.getMax() == 100);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenDatabasePropertyQueriedthenReturnsProperty() {
|
||||
Assert.assertTrue(databaseProperties.getUrl().equals("jdbc:postgresql:/localhost:5432"));
|
||||
Assert.assertTrue(databaseProperties.getUsername().equals("foo"));
|
||||
Assert.assertTrue(databaseProperties.getPassword().equals("bar"));
|
||||
}
|
||||
}
|
||||
|
@ -4,26 +4,28 @@ import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import com.baeldung.properties.ConfigPropertiesDemoApplication;
|
||||
import com.baeldung.properties.Database;
|
||||
import com.baeldung.configurationproperties.Database;
|
||||
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(classes = ConfigPropertiesDemoApplication.class)
|
||||
@TestPropertySource("classpath:application.properties")
|
||||
@SpringBootTest(classes = DatabaseConfigPropertiesApp.class)
|
||||
@TestPropertySource("classpath:database-test.properties")
|
||||
public class DatabasePropertiesIntegrationTest {
|
||||
|
||||
@Autowired
|
||||
@Qualifier("dataSource")
|
||||
private Database database;
|
||||
|
||||
@Test
|
||||
public void testDatabaseProperties() {
|
||||
Assert.assertNotNull(database);
|
||||
Assert.assertEquals("jdbc:postgresql:/localhost:5432/instance", database.getUrl());
|
||||
Assert.assertEquals("jdbc:postgresql:/localhost:5432", database.getUrl());
|
||||
Assert.assertEquals("foo", database.getUsername());
|
||||
Assert.assertEquals("bar", database.getPassword());
|
||||
}
|
||||
|
@ -3,6 +3,3 @@ spring.properties.refreshDelay=1000
|
||||
spring.config.location=file:extra.properties
|
||||
spring.main.allow-bean-definition-overriding=true
|
||||
|
||||
database.url=jdbc:postgresql:/localhost:5432/instance
|
||||
database.username=foo
|
||||
database.password=bar
|
@ -37,7 +37,7 @@
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<dependency>
|
||||
<groupId>org.hibernate</groupId>
|
||||
<artifactId>hibernate-core</artifactId>
|
||||
<version>${hibernate.version}</version>
|
||||
@ -53,7 +53,19 @@
|
||||
<groupId>org.springdoc</groupId>
|
||||
<artifactId>springdoc-openapi-data-rest</artifactId>
|
||||
<version>${springdoc.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- restdocs -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.restdocs</groupId>
|
||||
<artifactId>spring-restdocs-mockmvc</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.restdocs</groupId>
|
||||
<artifactId>spring-restdocs-restassured</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
@ -62,13 +74,49 @@
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.asciidoctor</groupId>
|
||||
<artifactId>asciidoctor-maven-plugin</artifactId>
|
||||
<version>${asciidoctor-plugin.version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>generate-docs</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>process-asciidoc</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<backend>html</backend>
|
||||
<doctype>book</doctype>
|
||||
<attributes>
|
||||
<snippets>${snippetsDirectory}</snippets>
|
||||
</attributes>
|
||||
<sourceDirectory>src/main/resources/asciidocs</sourceDirectory>
|
||||
<outputDirectory>target/generated-docs</outputDirectory>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
<resources>
|
||||
<resource>
|
||||
<filtering>true</filtering>
|
||||
<directory>src/main/resources</directory>
|
||||
<includes>
|
||||
<include>application.properties</include>
|
||||
<include>data.sql</include>
|
||||
<include>schema.sql</include>
|
||||
</includes>
|
||||
</resource>
|
||||
</resources>
|
||||
</build>
|
||||
|
||||
<properties>
|
||||
<java.version>1.8</java.version>
|
||||
<hibernate.version>5.2.10.Final</hibernate.version>
|
||||
<springdoc.version>1.2.32</springdoc.version>
|
||||
<asciidoctor-plugin.version>1.5.6</asciidoctor-plugin.version>
|
||||
<snippetsDirectory>${project.build.directory}/generated-snippets</snippetsDirectory>
|
||||
</properties>
|
||||
|
||||
<profiles>
|
||||
|
@ -0,0 +1,28 @@
|
||||
package com.baeldung.restdocopenapi;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
||||
import io.swagger.v3.oas.models.OpenAPI;
|
||||
import io.swagger.v3.oas.models.info.Info;
|
||||
import io.swagger.v3.oas.models.info.License;
|
||||
|
||||
@SpringBootApplication()
|
||||
public class Application {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(Application.class, args);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public OpenAPI customOpenAPI(@Value("${springdoc.version}") String appVersion) {
|
||||
return new OpenAPI().info(new Info().title("Foobar API")
|
||||
.version(appVersion)
|
||||
.description("This is a sample Foobar server created using springdocs - a library for OpenAPI 3 with spring boot.")
|
||||
.termsOfService("http://swagger.io/terms/")
|
||||
.license(new License().name("Apache 2.0")
|
||||
.url("http://springdoc.org")));
|
||||
}
|
||||
}
|
@ -0,0 +1,93 @@
|
||||
package com.baeldung.restdocopenapi;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
|
||||
@Entity
|
||||
public class Foo {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@Column(nullable = false)
|
||||
private String title;
|
||||
|
||||
@Column()
|
||||
private String body;
|
||||
|
||||
|
||||
protected Foo() {
|
||||
}
|
||||
|
||||
public Foo(long id, String title, String body) {
|
||||
this.id = id;
|
||||
this.title = title;
|
||||
this.body = body;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public String getBody() {
|
||||
return body;
|
||||
}
|
||||
|
||||
public void setBody(String body) {
|
||||
this.body = body;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result;
|
||||
result = prime * result + ((id == null) ? 0 : id.hashCode());
|
||||
result = prime * result + ((title == null) ? 0 : title.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
Foo other = (Foo) obj;
|
||||
if (id == null) {
|
||||
if (other.id != null)
|
||||
return false;
|
||||
} else if (!id.equals(other.id))
|
||||
return false;
|
||||
if (title == null) {
|
||||
if (other.title != null)
|
||||
return false;
|
||||
} else if (!title.equals(other.title))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Foo [id=" + id + ", title=" + title + "]";
|
||||
}
|
||||
}
|
@ -0,0 +1,83 @@
|
||||
package com.baeldung.restdocopenapi;
|
||||
|
||||
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.validation.Valid;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/foo")
|
||||
public class FooController {
|
||||
|
||||
@Autowired
|
||||
FooRepository repository;
|
||||
|
||||
@GetMapping
|
||||
public ResponseEntity<List<Foo>> getAllFoos() {
|
||||
List<Foo> fooList = (List<Foo>) repository.findAll();
|
||||
if (fooList.isEmpty()) {
|
||||
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
||||
}
|
||||
return new ResponseEntity<>(fooList, HttpStatus.OK);
|
||||
}
|
||||
|
||||
@GetMapping(value = "{id}")
|
||||
public ResponseEntity<Foo> getFooById(@PathVariable("id") Long id) {
|
||||
|
||||
Optional<Foo> foo = repository.findById(id);
|
||||
return foo.isPresent() ? new ResponseEntity<>(foo.get(), HttpStatus.OK) : new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public ResponseEntity<Foo> addFoo(@RequestBody @Valid Foo foo) {
|
||||
HttpHeaders httpHeaders = new HttpHeaders();
|
||||
httpHeaders.setLocation(linkTo(FooController.class).slash(foo.getId())
|
||||
.toUri());
|
||||
Foo savedFoo;
|
||||
try {
|
||||
savedFoo = repository.save(foo);
|
||||
} catch (Exception e) {
|
||||
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
|
||||
}
|
||||
|
||||
return new ResponseEntity<>(savedFoo, httpHeaders, HttpStatus.CREATED);
|
||||
}
|
||||
|
||||
@DeleteMapping("/{id}")
|
||||
public ResponseEntity<Void> deleteFoo(@PathVariable("id") long id) {
|
||||
try {
|
||||
repository.deleteById(id);
|
||||
} catch (Exception e) {
|
||||
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
|
||||
}
|
||||
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
|
||||
}
|
||||
|
||||
@PutMapping("/{id}")
|
||||
public ResponseEntity<Foo> updateFoo(@PathVariable("id") long id, @RequestBody Foo foo) {
|
||||
boolean isFooPresent = repository.existsById(Long.valueOf(id));
|
||||
|
||||
if (!isFooPresent) {
|
||||
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
||||
}
|
||||
|
||||
Foo updatedFoo = repository.save(foo);
|
||||
|
||||
return new ResponseEntity<>(updatedFoo, HttpStatus.OK);
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package com.baeldung.restdocopenapi;
|
||||
|
||||
import org.springframework.data.repository.PagingAndSortingRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public interface FooRepository extends PagingAndSortingRepository<Foo, Long>{
|
||||
|
||||
}
|
@ -0,0 +1,121 @@
|
||||
package com.baeldung.restdocopenapi.springdoc;
|
||||
|
||||
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.validation.Valid;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.baeldung.restdocopenapi.Foo;
|
||||
import com.baeldung.restdocopenapi.FooRepository;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.media.ArraySchema;
|
||||
import io.swagger.v3.oas.annotations.media.Content;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponses;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/foobar")
|
||||
@Tag(name = "foobar", description = "the foobar API with documentation annotations")
|
||||
public class FooBarController {
|
||||
|
||||
@Autowired
|
||||
FooRepository repository;
|
||||
|
||||
@Operation(summary = "Get all foos")
|
||||
@ApiResponses(value = {
|
||||
@ApiResponse(responseCode = "200", description = "found foos", content = {
|
||||
@Content(mediaType = "application/json", array = @ArraySchema(schema = @Schema(implementation = Foo.class)))}),
|
||||
@ApiResponse(responseCode = "404", description = "No Foos found", content = @Content) })
|
||||
@GetMapping
|
||||
public ResponseEntity<List<Foo>> getAllFoos() {
|
||||
List<Foo> fooList = (List<Foo>) repository.findAll();
|
||||
if (fooList.isEmpty()) {
|
||||
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
||||
}
|
||||
return new ResponseEntity<>(fooList, HttpStatus.OK);
|
||||
}
|
||||
|
||||
@Operation(summary = "Get a foo by foo id")
|
||||
@ApiResponses(value = {
|
||||
@ApiResponse(responseCode = "200", description = "found the foo", content = {
|
||||
@Content(mediaType = "application/json", schema = @Schema(implementation = Foo.class))}),
|
||||
@ApiResponse(responseCode = "400", description = "Invalid id supplied", content = @Content),
|
||||
@ApiResponse(responseCode = "404", description = "Foo not found", content = @Content) })
|
||||
@GetMapping(value = "{id}")
|
||||
public ResponseEntity<Foo> getFooById(@Parameter(description = "id of foo to be searched") @PathVariable("id") String id) {
|
||||
|
||||
Optional<Foo> foo = repository.findById(Long.valueOf(id));
|
||||
return foo.isPresent() ? new ResponseEntity<>(foo.get(), HttpStatus.OK) : new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
||||
}
|
||||
|
||||
@Operation(summary = "Create a foo")
|
||||
@ApiResponses(value = {
|
||||
@ApiResponse(responseCode = "201", description = "foo created", content = { @
|
||||
Content(mediaType = "application/json", schema = @Schema(implementation = Foo.class))}),
|
||||
@ApiResponse(responseCode = "404", description = "Bad request", content = @Content) })
|
||||
@PostMapping
|
||||
public ResponseEntity<Foo> addFoo(@Parameter(description = "foo object to be created") @RequestBody @Valid Foo foo) {
|
||||
HttpHeaders httpHeaders = new HttpHeaders();
|
||||
httpHeaders.setLocation(linkTo(FooBarController.class).slash(foo.getId()).toUri());
|
||||
Foo savedFoo;
|
||||
try {
|
||||
savedFoo = repository.save(foo);
|
||||
} catch (Exception e) {
|
||||
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
|
||||
}
|
||||
|
||||
return new ResponseEntity<>(savedFoo, httpHeaders, HttpStatus.CREATED);
|
||||
}
|
||||
|
||||
@Operation(summary = "Delete a foo")
|
||||
@ApiResponses(value = {
|
||||
@ApiResponse(responseCode = "204", description = "foo deleted"),
|
||||
@ApiResponse(responseCode = "404", description = "Bad request", content = @Content) })
|
||||
@DeleteMapping("/{id}")
|
||||
public ResponseEntity<Void> deleteFoo(@Parameter(description = "id of foo to be deleted") @PathVariable("id") long id) {
|
||||
try {
|
||||
repository.deleteById(id);
|
||||
} catch (Exception e) {
|
||||
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
|
||||
}
|
||||
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
|
||||
}
|
||||
|
||||
@Operation(summary = "Update a foo")
|
||||
@ApiResponses(value = {
|
||||
@ApiResponse(responseCode = "200", description = "foo updated successfully", content = {
|
||||
@Content(mediaType = "application/json", schema = @Schema(implementation = Foo.class))}),
|
||||
@ApiResponse(responseCode = "404", description = "No Foo exists with given id", content = @Content) })
|
||||
@PutMapping("/{id}")
|
||||
public ResponseEntity<Foo> updateFoo(@Parameter(description = "id of foo to be updated") @PathVariable("id") long id, @RequestBody Foo foo) {
|
||||
|
||||
boolean isFooPresent = repository.existsById(Long.valueOf(id));
|
||||
|
||||
if (!isFooPresent) {
|
||||
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
||||
}
|
||||
|
||||
Foo updatedFoo = repository.save(foo);
|
||||
|
||||
return new ResponseEntity<>(updatedFoo, HttpStatus.OK);
|
||||
}
|
||||
}
|
@ -5,4 +5,7 @@ springdoc.swagger-ui.path=/swagger-ui-custom.html
|
||||
springdoc.api-docs.path=/api-docs
|
||||
|
||||
# H2 Related Configurations
|
||||
spring.datasource.url=jdbc:h2:mem:springdoc
|
||||
spring.datasource.url=jdbc:h2:mem:springdoc
|
||||
|
||||
springdoc.version=@springdoc.version@
|
||||
spring.jpa.hibernate.ddl-auto=none
|
@ -0,0 +1,153 @@
|
||||
= RESTful Notes API Guide
|
||||
Baeldung;
|
||||
:doctype: book
|
||||
:icons: font
|
||||
:source-highlighter: highlightjs
|
||||
:toc: left
|
||||
:toclevels: 4
|
||||
:sectlinks:
|
||||
|
||||
[[overview]]
|
||||
= Overview
|
||||
|
||||
[[overview-http-verbs]]
|
||||
== HTTP verbs
|
||||
|
||||
RESTful notes tries to adhere as closely as possible to standard HTTP and REST conventions in its
|
||||
use of HTTP verbs.
|
||||
|
||||
|===
|
||||
| Verb | Usage
|
||||
|
||||
| `GET`
|
||||
| Used to retrieve a resource
|
||||
|
||||
| `POST`
|
||||
| Used to create a new resource
|
||||
|
||||
| `PUT`
|
||||
| Used to update an existing resource
|
||||
|
||||
| `DELETE`
|
||||
| Used to delete an existing resource
|
||||
|===
|
||||
|
||||
RESTful notes tries to adhere as closely as possible to standard HTTP and REST conventions in its
|
||||
use of HTTP status codes.
|
||||
|
||||
|===
|
||||
| Status code | Usage
|
||||
|
||||
| `200 OK`
|
||||
| The request completed successfully
|
||||
|
||||
| `201 Created`
|
||||
| A new resource has been created successfully. The resource's URI is available from the response's
|
||||
`Location` header
|
||||
|
||||
| `204 No Content`
|
||||
| An update to an existing resource has been applied successfully
|
||||
|
||||
| `400 Bad Request`
|
||||
| The request was malformed. The response body will include an error providing further information
|
||||
|
||||
| `404 Not Found`
|
||||
| The requested resource did not exist
|
||||
|===
|
||||
|
||||
[[overview-hypermedia]]
|
||||
== Hypermedia
|
||||
|
||||
RESTful Notes uses hypermedia and resources include links to other resources in their
|
||||
responses. Responses are in http://stateless.co/hal_specification.html[Hypertext Application
|
||||
from resource to resource.
|
||||
Language (HAL)] format. Links can be found beneath the `_links` key. Users of the API should
|
||||
not create URIs themselves, instead they should use the above-described links to navigate
|
||||
|
||||
[[resources]]
|
||||
= Resources
|
||||
|
||||
[[resources-FOO]]
|
||||
== FOO REST Service
|
||||
|
||||
The FOO provides the entry point into the service.
|
||||
|
||||
[[resources-foo-get]]
|
||||
=== Accessing the foo GET
|
||||
|
||||
A `GET` request is used to access the foo read.
|
||||
|
||||
==== Request structure
|
||||
|
||||
include::{snippets}/getAFoo/http-request.adoc[]
|
||||
|
||||
==== Path Parameters
|
||||
include::{snippets}/getAFoo/path-parameters.adoc[]
|
||||
|
||||
==== Example response
|
||||
|
||||
include::{snippets}/getAFoo/http-response.adoc[]
|
||||
|
||||
==== CURL request
|
||||
|
||||
include::{snippets}/getAFoo/curl-request.adoc[]
|
||||
|
||||
[[resources-foo-post]]
|
||||
=== Accessing the foo POST
|
||||
|
||||
A `POST` request is used to access the foo create.
|
||||
|
||||
==== Request structure
|
||||
|
||||
include::{snippets}/createFoo/http-request.adoc[]
|
||||
|
||||
==== Example response
|
||||
|
||||
include::{snippets}/createFoo/http-response.adoc[]
|
||||
|
||||
==== CURL request
|
||||
|
||||
include::{snippets}/createFoo/curl-request.adoc[]
|
||||
|
||||
[[resources-foo-delete]]
|
||||
=== Accessing the foo DELETE
|
||||
|
||||
A `DELETE` request is used to access the foo delete.
|
||||
|
||||
==== Request structure
|
||||
|
||||
include::{snippets}/deleteFoo/http-request.adoc[]
|
||||
|
||||
==== Path Parameters
|
||||
include::{snippets}/deleteFoo/path-parameters.adoc[]
|
||||
|
||||
==== Example response
|
||||
|
||||
include::{snippets}/deleteFoo/http-response.adoc[]
|
||||
|
||||
==== CURL request
|
||||
|
||||
include::{snippets}/deleteFoo/curl-request.adoc[]
|
||||
|
||||
[[resources-foo-put]]
|
||||
=== Accessing the foo PUT
|
||||
|
||||
A `PUT` request is used to access the foo update.
|
||||
|
||||
==== Request structure
|
||||
|
||||
include::{snippets}/updateFoo/http-request.adoc[]
|
||||
|
||||
==== Path Parameters
|
||||
include::{snippets}/updateFoo/path-parameters.adoc[]
|
||||
|
||||
==== Example response
|
||||
|
||||
include::{snippets}/updateFoo/http-response.adoc[]
|
||||
|
||||
==== CURL request
|
||||
|
||||
include::{snippets}/updateFoo/curl-request.adoc[]
|
||||
|
||||
|
||||
|
@ -0,0 +1,4 @@
|
||||
INSERT INTO Foo(id, title, body) VALUES (1, 'Foo 1', 'Foo body 1');
|
||||
INSERT INTO Foo(id, title, body) VALUES (2, 'Foo 2', 'Foo body 2');
|
||||
INSERT INTO Foo(id, title, body) VALUES (3, 'Foo 3', 'Foo body 3');
|
||||
|
@ -0,0 +1,8 @@
|
||||
DROP TABLE IF EXISTS foo;
|
||||
|
||||
CREATE TABLE foo (
|
||||
id INTEGER NOT NULL AUTO_INCREMENT,
|
||||
title VARCHAR(250) NOT NULL,
|
||||
body VARCHAR(250),
|
||||
PRIMARY KEY (id)
|
||||
);
|
@ -0,0 +1,120 @@
|
||||
package com.baeldung.restdocopenapi.restdoc;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
|
||||
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.documentationConfiguration;
|
||||
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.delete;
|
||||
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get;
|
||||
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post;
|
||||
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.put;
|
||||
import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessRequest;
|
||||
import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse;
|
||||
import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint;
|
||||
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
|
||||
import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields;
|
||||
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
|
||||
import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName;
|
||||
import static org.springframework.restdocs.request.RequestDocumentation.pathParameters;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
import static org.springframework.util.StringUtils.collectionToDelimitedString;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.hateoas.MediaTypes;
|
||||
import org.springframework.restdocs.RestDocumentationContextProvider;
|
||||
import org.springframework.restdocs.RestDocumentationExtension;
|
||||
import org.springframework.restdocs.constraints.ConstraintDescriptions;
|
||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
|
||||
import com.baeldung.restdocopenapi.Application;
|
||||
import com.baeldung.restdocopenapi.Foo;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
@ExtendWith({ RestDocumentationExtension.class, SpringExtension.class })
|
||||
@SpringBootTest(classes = Application.class)
|
||||
public class SpringRestDocsUnitTest {
|
||||
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@Autowired
|
||||
private ObjectMapper objectMapper;
|
||||
|
||||
@BeforeEach
|
||||
public void setup(WebApplicationContext webApplicationContext, RestDocumentationContextProvider restDocumentation) {
|
||||
this.mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext)
|
||||
.apply(documentationConfiguration(restDocumentation))
|
||||
.build();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenGetFoo_thenSuccessful() throws Exception {
|
||||
this.mockMvc.perform(get("/foo"))
|
||||
.andDo(print())
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().string(containsString("Foo 1")))
|
||||
.andDo(document("getAllFoos"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenGetFooById_thenSuccessful() throws Exception {
|
||||
ConstraintDescriptions desc = new ConstraintDescriptions(Foo.class);
|
||||
|
||||
this.mockMvc.perform(get("/foo/{id}", 1))
|
||||
.andExpect(status().isOk())
|
||||
.andDo(document("getAFoo", preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint()),
|
||||
pathParameters(parameterWithName("id").description("id of foo to be searched")),
|
||||
responseFields(fieldWithPath("id").description("The id of the foo" + collectionToDelimitedString(desc.descriptionsForProperty("id"), ". ")),
|
||||
fieldWithPath("title").description("The title of the foo"), fieldWithPath("body").description("The body of the foo"))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenPostFoo_thenSuccessful() throws Exception {
|
||||
Map<String, Object> foo = new HashMap<>();
|
||||
foo.put("id", 4L);
|
||||
foo.put("title", "New Foo");
|
||||
foo.put("body", "Body of New Foo");
|
||||
|
||||
this.mockMvc.perform(post("/foo").contentType(MediaTypes.HAL_JSON)
|
||||
.content(this.objectMapper.writeValueAsString(foo)))
|
||||
.andExpect(status().isCreated())
|
||||
.andDo(document("createFoo", preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint()), requestFields(fieldWithPath("id").description("The id of the foo"), fieldWithPath("title").description("The title of the foo"),
|
||||
fieldWithPath("body").description("The body of the foo"))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenDeleteFoo_thenSuccessful() throws Exception {
|
||||
this.mockMvc.perform(delete("/foo/{id}", 2))
|
||||
.andExpect(status().isNoContent())
|
||||
.andDo(document("deleteFoo", pathParameters(parameterWithName("id").description("The id of the foo to delete"))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenUpdateFoo_thenSuccessful() throws Exception {
|
||||
|
||||
ConstraintDescriptions desc = new ConstraintDescriptions(Foo.class);
|
||||
|
||||
Map<String, Object> foo = new HashMap<>();
|
||||
foo.put("title", "Updated Foo");
|
||||
foo.put("body", "Body of Updated Foo");
|
||||
|
||||
this.mockMvc.perform(put("/foo/{id}", 3).contentType(MediaTypes.HAL_JSON)
|
||||
.content(this.objectMapper.writeValueAsString(foo)))
|
||||
.andExpect(status().isOk())
|
||||
.andDo(document("updateFoo", pathParameters(parameterWithName("id").description("The id of the foo to update")),
|
||||
responseFields(fieldWithPath("id").description("The id of the updated foo" + collectionToDelimitedString(desc.descriptionsForProperty("id"), ". ")),
|
||||
fieldWithPath("title").description("The title of the updated foo"), fieldWithPath("body").description("The body of the updated foo"))));
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -33,7 +33,7 @@
|
||||
</dependencies>
|
||||
|
||||
<properties>
|
||||
<spring-kafka.version>2.2.7.RELEASE</spring-kafka.version>
|
||||
<spring-kafka.version>2.3.7.RELEASE</spring-kafka.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
Loading…
x
Reference in New Issue
Block a user