Merge branch 'master' into BAEL-12731
This commit is contained in:
commit
5b9fb323af
|
@ -1,12 +1,7 @@
|
|||
issuer:
|
||||
uri: http://localhost:8080/uaa
|
||||
|
||||
spring_profiles: postgresql,default
|
||||
|
||||
database.driverClassName: org.postgresql.Driver
|
||||
database.url: jdbc:postgresql:uaadb2
|
||||
database.username: postgres
|
||||
database.password: postgres
|
||||
spring_profiles: default,hsqldb
|
||||
|
||||
encryption:
|
||||
active_key_label: CHANGE-THIS-KEY
|
||||
|
|
|
@ -1,23 +1,11 @@
|
|||
# SECURITY OAUTH2 CLIENT (OAuth2ClientProperties)
|
||||
#spring.security.oauth2.client.provider.*= # OAuth provider details.
|
||||
#spring.security.oauth2.client.registration.*= # OAuth client registrations.
|
||||
|
||||
server.port=8081
|
||||
#server.servlet.context-path=/uaa-client-webapp
|
||||
|
||||
uaa.url=http://localhost:8080/uaa
|
||||
resource.server.url=http://localhost:8082
|
||||
|
||||
spring.security.oauth2.client.registration.uaa.client-name=UAA OAuth2 Client
|
||||
spring.security.oauth2.client.registration.uaa.client-id=client1
|
||||
spring.security.oauth2.client.registration.uaa.client-secret=client1
|
||||
spring.security.oauth2.client.registration.uaa.authorization-grant-type=authorization_code
|
||||
spring.security.oauth2.client.registration.uaa.client-name=Web App Client
|
||||
spring.security.oauth2.client.registration.uaa.client-id=webappclient
|
||||
spring.security.oauth2.client.registration.uaa.client-secret=webappclientsecret
|
||||
spring.security.oauth2.client.registration.uaa.scope=resource.read,resource.write,openid,profile
|
||||
spring.security.oauth2.client.registration.uaa.redirect-uri=http://localhost:8081/login/oauth2/code/uaa
|
||||
#spring.security.oauth2.client.registration.uaa.redirect-uri=http://localhost:8081/**
|
||||
|
||||
spring.security.oauth2.client.provider.uaa.token-uri=${uaa.url}/oauth/token
|
||||
spring.security.oauth2.client.provider.uaa.authorization-uri=${uaa.url}/oauth/authorize
|
||||
spring.security.oauth2.client.provider.uaa.jwk-set-uri=${uaa.url}/token_keys
|
||||
spring.security.oauth2.client.provider.uaa.user-info-uri=${uaa.url}/userinfo
|
||||
spring.security.oauth2.client.provider.uaa.user-name-attribute=user_name
|
||||
spring.security.oauth2.client.provider.uaa.issuer-uri=http://localhost:8080/uaa/oauth/token
|
||||
|
||||
|
|
|
@ -1,16 +1,3 @@
|
|||
server.port=8082
|
||||
|
||||
uaa.url=http://localhost:8080/uaa
|
||||
|
||||
#approch1
|
||||
spring.security.oauth2.resourceserver.jwt.issuer-uri=${uaa.url}/oauth/token
|
||||
|
||||
#approch2
|
||||
#spring.security.oauth2.resourceserver.jwt.jwk-set-uri=${uaa.url}/token_key
|
||||
|
||||
# SECURITY OAUTH2 CLIENT (OAuth2ClientProperties)
|
||||
#security.oauth2.client.client-id=client1
|
||||
#security.oauth2.client.client-secret=client1
|
||||
|
||||
#security.oauth2.resource.jwt.key-uri=${uaa.url}/token_key
|
||||
#security.oauth2.resource.token-info-uri=${uaa.url}/oauth/check_token
|
||||
spring.security.oauth2.resourceserver.jwt.issuer-uri=http://localhost:8080/uaa/oauth/token
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
package com.baeldung
|
||||
|
||||
class Person {
|
||||
private String firstname
|
||||
private String lastname
|
||||
private Integer age
|
||||
|
||||
Person(String firstname, String lastname, Integer age) {
|
||||
this.firstname = firstname
|
||||
this.lastname = lastname
|
||||
this.age = age
|
||||
}
|
||||
|
||||
String getFirstname() {
|
||||
return firstname
|
||||
}
|
||||
|
||||
void setFirstname(String firstname) {
|
||||
this.firstname = firstname
|
||||
}
|
||||
|
||||
String getLastname() {
|
||||
return lastname
|
||||
}
|
||||
|
||||
void setLastname(String lastname) {
|
||||
this.lastname = lastname
|
||||
}
|
||||
|
||||
Integer getAge() {
|
||||
return age
|
||||
}
|
||||
|
||||
void setAge(Integer age) {
|
||||
this.age = age
|
||||
}
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
package com.baeldung.closures
|
||||
|
||||
class Closures {
|
||||
|
||||
def printWelcome = {
|
||||
println "Welcome to Closures!"
|
||||
}
|
||||
|
||||
def print = { name ->
|
||||
println name
|
||||
}
|
||||
|
||||
def formatToLowerCase(name) {
|
||||
return name.toLowerCase()
|
||||
}
|
||||
def formatToLowerCaseClosure = { name ->
|
||||
return name.toLowerCase()
|
||||
}
|
||||
|
||||
def count=0
|
||||
|
||||
def increaseCount = {
|
||||
count++
|
||||
}
|
||||
|
||||
def greet = {
|
||||
return "Hello! ${it}"
|
||||
}
|
||||
|
||||
def multiply = { x, y ->
|
||||
return x*y
|
||||
}
|
||||
|
||||
def calculate = {int x, int y, String operation ->
|
||||
|
||||
//log closure
|
||||
def log = {
|
||||
println "Performing $it"
|
||||
}
|
||||
|
||||
def result = 0
|
||||
switch(operation) {
|
||||
case "ADD":
|
||||
log("Addition")
|
||||
result = x+y
|
||||
break
|
||||
case "SUB":
|
||||
log("Subtraction")
|
||||
result = x-y
|
||||
break
|
||||
case "MUL":
|
||||
log("Multiplication")
|
||||
result = x*y
|
||||
break
|
||||
case "DIV":
|
||||
log("Division")
|
||||
result = x/y
|
||||
break
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
def addAll = { int... args ->
|
||||
return args.sum()
|
||||
}
|
||||
|
||||
def volume(Closure areaCalculator, int... dimensions) {
|
||||
if(dimensions.size() == 3) {
|
||||
|
||||
//consider dimension[0] = length, dimension[1] = breadth, dimension[2] = height
|
||||
//for cube and cuboid
|
||||
return areaCalculator(dimensions[0], dimensions[1]) * dimensions[2]
|
||||
} else if(dimensions.size() == 2) {
|
||||
|
||||
//consider dimension[0] = radius, dimension[1] = height
|
||||
//for cylinder and cone
|
||||
return areaCalculator(dimensions[0]) * dimensions[1]
|
||||
} else if(dimensions.size() == 1) {
|
||||
|
||||
//consider dimension[0] = radius
|
||||
//for sphere
|
||||
return areaCalculator(dimensions[0]) * dimensions[0]
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
package com.baeldung.closures
|
||||
|
||||
class Employee {
|
||||
|
||||
String fullName
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
package com.baeldung.closures
|
||||
|
||||
import spock.lang.Specification
|
||||
|
||||
class ClosuresUnitTest extends GroovyTestCase {
|
||||
|
||||
Closures closures = new Closures()
|
||||
|
||||
void testDeclaration() {
|
||||
|
||||
closures.print("Hello! Closure")
|
||||
closures.formatToLowerCaseClosure("Hello! Closure")
|
||||
|
||||
closures.print.call("Hello! Closure")
|
||||
closures.formatToLowerCaseClosure.call("Hello! Closure")
|
||||
|
||||
}
|
||||
|
||||
void testClosureVsMethods() {
|
||||
assert closures.formatToLowerCase("TONY STARK") == closures.formatToLowerCaseClosure("Tony STark")
|
||||
}
|
||||
|
||||
void testParameters() {
|
||||
//implicit parameter
|
||||
assert closures.greet("Alex") == "Hello! Alex"
|
||||
|
||||
//multiple parameters
|
||||
assert closures.multiply(2, 4) == 8
|
||||
|
||||
assert closures.calculate(12, 4, "ADD") == 16
|
||||
assert closures.calculate(12, 4, "SUB") == 8
|
||||
assert closures.calculate(43, 8, "DIV") == 5.375
|
||||
|
||||
//varags
|
||||
assert closures.addAll(12, 10, 14) == 36
|
||||
|
||||
}
|
||||
|
||||
void testClosureAsAnArgument() {
|
||||
assert closures.volume({ l, b -> return l*b }, 12, 6, 10) == 720
|
||||
|
||||
assert closures.volume({ radius -> return Math.PI*radius*radius/3 }, 5, 10) == Math.PI * 250/3
|
||||
}
|
||||
|
||||
void testGStringsLazyEvaluation() {
|
||||
def name = "Samwell"
|
||||
def welcomeMsg = "Welcome! $name"
|
||||
|
||||
assert welcomeMsg == "Welcome! Samwell"
|
||||
|
||||
// changing the name does not affect original interpolated value
|
||||
name = "Tarly"
|
||||
assert welcomeMsg != "Welcome! Tarly"
|
||||
|
||||
def fullName = "Tarly Samson"
|
||||
def greetStr = "Hello! ${-> fullName}"
|
||||
|
||||
assert greetStr == "Hello! Tarly Samson"
|
||||
|
||||
// this time changing the variable affects the interpolated String's value
|
||||
fullName = "Jon Smith"
|
||||
assert greetStr == "Hello! Jon Smith"
|
||||
}
|
||||
|
||||
void testClosureInLists() {
|
||||
def list = [10, 11, 12, 13, 14, true, false, "BUNTHER"]
|
||||
list.each {
|
||||
println it
|
||||
}
|
||||
|
||||
assert [13, 14] == list.findAll{ it instanceof Integer && it >= 13}
|
||||
}
|
||||
|
||||
void testClosureInMaps() {
|
||||
def map = [1:10, 2:30, 4:5]
|
||||
|
||||
assert [10, 60, 20] == map.collect{it.key * it.value}
|
||||
}
|
||||
|
||||
}
|
|
@ -129,13 +129,13 @@ class ListTest{
|
|||
assertTrue(filterList.findAll{it > 3} == [4, 5, 6, 76])
|
||||
|
||||
assertTrue(filterList.findAll{ it instanceof Number} == [2, 1, 3, 4, 5, 6, 76])
|
||||
|
||||
|
||||
assertTrue(filterList.grep( Number )== [2, 1, 3, 4, 5, 6, 76])
|
||||
|
||||
|
||||
assertTrue(filterList.grep{ it> 6 }== [76])
|
||||
|
||||
def conditionList = [2, 1, 3, 4, 5, 6, 76]
|
||||
|
||||
|
||||
assertFalse(conditionList.every{ it < 6})
|
||||
|
||||
assertTrue(conditionList.any{ it%2 == 0})
|
||||
|
@ -165,7 +165,7 @@ class ListTest{
|
|||
|
||||
def strList = ["na", "ppp", "as"]
|
||||
assertTrue(strList.max() == "ppp")
|
||||
|
||||
|
||||
Comparator minc = {a,b -> a == b? 0: a < b? -1 : 1}
|
||||
def numberList = [3, 2, 0, 7]
|
||||
assertTrue(numberList.min(minc) == 0)
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
package com.baeldung.lists
|
||||
|
||||
import com.baeldung.Person
|
||||
import org.junit.Test
|
||||
|
||||
import static org.junit.Assert.*
|
||||
|
||||
class ListUnitTest {
|
||||
|
||||
private final personList = [
|
||||
new Person("Regina", "Fitzpatrick", 25),
|
||||
new Person("Abagail", "Ballard", 26),
|
||||
new Person("Lucian", "Walter", 30),
|
||||
]
|
||||
|
||||
@Test
|
||||
void whenListContainsElement_thenCheckReturnsTrue() {
|
||||
def list = ['a', 'b', 'c']
|
||||
|
||||
assertTrue(list.indexOf('a') > -1)
|
||||
assertTrue(list.contains('a'))
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenListContainsElement_thenCheckWithMembershipOperatorReturnsTrue() {
|
||||
def list = ['a', 'b', 'c']
|
||||
|
||||
assertTrue('a' in list)
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenListOfPerson_whenUsingStreamMatching_thenShouldEvaluateList() {
|
||||
assertTrue(personList.stream().anyMatch {it.age > 20})
|
||||
assertFalse(personList.stream().allMatch {it.age < 30})
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenListOfPerson_whenUsingCollectionMatching_thenShouldEvaluateList() {
|
||||
assertTrue(personList.any {it.age > 20})
|
||||
assertFalse(personList.every {it.age < 30})
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenListOfPerson_whenUsingStreamFind_thenShouldReturnMatchingElements() {
|
||||
assertTrue(personList.stream().filter {it.age > 20}.findAny().isPresent())
|
||||
assertFalse(personList.stream().filter {it.age > 30}.findAny().isPresent())
|
||||
assertTrue(personList.stream().filter {it.age > 20}.findAll().size() == 3)
|
||||
assertTrue(personList.stream().filter {it.age > 30}.findAll().isEmpty())
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenListOfPerson_whenUsingCollectionFind_thenShouldReturnMatchingElements() {
|
||||
assertNotNull(personList.find {it.age > 20})
|
||||
assertNull(personList.find {it.age > 30})
|
||||
assertTrue(personList.findAll {it.age > 20}.size() == 3)
|
||||
assertTrue(personList.findAll {it.age > 30}.isEmpty())
|
||||
}
|
||||
}
|
|
@ -1,10 +1,18 @@
|
|||
package com.baeldung.map
|
||||
|
||||
import static org.junit.Assert.*
|
||||
import com.baeldung.Person
|
||||
import org.junit.Test
|
||||
|
||||
import static org.junit.Assert.*
|
||||
|
||||
class MapUnitTest {
|
||||
|
||||
private final personMap = [
|
||||
Regina : new Person("Regina", "Fitzpatrick", 25),
|
||||
Abagail: new Person("Abagail", "Ballard", 26),
|
||||
Lucian : new Person("Lucian", "Walter", 30)
|
||||
]
|
||||
|
||||
@Test
|
||||
void whenUsingEach_thenMapIsIterated() {
|
||||
def map = [
|
||||
|
@ -63,7 +71,7 @@ class MapUnitTest {
|
|||
'FF6347' : 'Tomato',
|
||||
'FF4500' : 'Orange Red'
|
||||
]
|
||||
|
||||
|
||||
map.eachWithIndex { key, val, index ->
|
||||
def indent = ((index == 0 || index % 2 == 0) ? " " : "")
|
||||
println "$indent Hex Code: $key = Color Name: $val"
|
||||
|
@ -82,4 +90,65 @@ class MapUnitTest {
|
|||
println "Hex Code: $entry.key = Color Name: $entry.value"
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenMapContainsKeyElement_thenCheckReturnsTrue() {
|
||||
def map = [a: 'd', b: 'e', c: 'f']
|
||||
|
||||
assertTrue(map.containsKey('a'))
|
||||
assertFalse(map.containsKey('e'))
|
||||
assertTrue(map.containsValue('e'))
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenMapContainsKeyElement_thenCheckByMembershipReturnsTrue() {
|
||||
def map = [a: 'd', b: 'e', c: 'f']
|
||||
|
||||
assertTrue('a' in map)
|
||||
assertFalse('f' in map)
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenMapContainsFalseBooleanValues_thenCheckReturnsFalse() {
|
||||
def map = [a: true, b: false, c: null]
|
||||
|
||||
assertTrue(map.containsKey('b'))
|
||||
assertTrue('a' in map)
|
||||
assertFalse('b' in map)
|
||||
assertFalse('c' in map)
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenMapOfPerson_whenUsingStreamMatching_thenShouldEvaluateMap() {
|
||||
assertTrue(personMap.keySet().stream().anyMatch {it == "Regina"})
|
||||
assertFalse(personMap.keySet().stream().allMatch {it == "Albert"})
|
||||
assertFalse(personMap.values().stream().allMatch {it.age < 30})
|
||||
assertTrue(personMap.entrySet().stream().anyMatch {it.key == "Abagail" && it.value.lastname == "Ballard"})
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenMapOfPerson_whenUsingCollectionMatching_thenShouldEvaluateMap() {
|
||||
assertTrue(personMap.keySet().any {it == "Regina"})
|
||||
assertFalse(personMap.keySet().every {it == "Albert"})
|
||||
assertFalse(personMap.values().every {it.age < 30})
|
||||
assertTrue(personMap.any {firstname, person -> firstname == "Abagail" && person.lastname == "Ballard"})
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenMapOfPerson_whenUsingCollectionFind_thenShouldReturnElements() {
|
||||
assertNotNull(personMap.find {it.key == "Abagail" && it.value.lastname == "Ballard"})
|
||||
assertTrue(personMap.findAll {it.value.age > 20}.size() == 3)
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenMapOfPerson_whenUsingStreamFind_thenShouldReturnElements() {
|
||||
assertTrue(
|
||||
personMap.entrySet().stream()
|
||||
.filter {it.key == "Abagail" && it.value.lastname == "Ballard"}
|
||||
.findAny().isPresent())
|
||||
assertTrue(
|
||||
personMap.entrySet().stream()
|
||||
.filter {it.value.age > 20}
|
||||
.findAll().size() == 3)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
package com.baeldung.set
|
||||
|
||||
import org.junit.Test
|
||||
|
||||
import static org.junit.Assert.assertTrue
|
||||
|
||||
class SetUnitTest {
|
||||
|
||||
@Test
|
||||
void whenSetContainsElement_thenCheckReturnsTrue() {
|
||||
def set = ['a', 'b', 'c'] as Set
|
||||
|
||||
assertTrue(set.contains('a'))
|
||||
assertTrue('a' in set)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package com.baeldung.jlink;
|
||||
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class HelloWorld {
|
||||
|
||||
private static final Logger LOG = Logger.getLogger(HelloWorld.class.getName());
|
||||
|
||||
public static void main(String[] args) {
|
||||
LOG.info("Hello World!");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
module jlinkModule {
|
||||
requires java.logging;
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
<?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>core-java-12</artifactId>
|
||||
<version>0.1.0-SNAPSHOT</version>
|
||||
<name>core-java-12</name>
|
||||
<packaging>jar</packaging>
|
||||
<url>http://maven.apache.org</url>
|
||||
|
||||
<parent>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>parent-modules</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.assertj</groupId>
|
||||
<artifactId>assertj-core</artifactId>
|
||||
<version>${assertj.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>${maven-compiler-plugin.version}</version>
|
||||
<configuration>
|
||||
<source>${maven.compiler.source.version}</source>
|
||||
<target>${maven.compiler.target.version}</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source.version>12</maven.compiler.source.version>
|
||||
<maven.compiler.target.version>12</maven.compiler.target.version>
|
||||
<assertj.version>3.6.1</assertj.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,71 @@
|
|||
package com.baeldung.collectors;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static java.util.stream.Collectors.maxBy;
|
||||
import static java.util.stream.Collectors.minBy;
|
||||
import static java.util.stream.Collectors.teeing;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Unit tests for collectors additions in Java 12.
|
||||
*/
|
||||
public class CollectorsUnitTest {
|
||||
|
||||
@Test
|
||||
public void whenTeeing_ItShouldCombineTheResultsAsExpected() {
|
||||
List<Integer> numbers = Arrays.asList(42, 4, 2, 24);
|
||||
Range range = numbers.stream()
|
||||
.collect(teeing(minBy(Integer::compareTo), maxBy(Integer::compareTo), (min, max) -> new Range(min.orElse(null), max.orElse(null))));
|
||||
|
||||
assertThat(range).isEqualTo(new Range(2, 42));
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a closed range of numbers between {@link #min} and
|
||||
* {@link #max}, both inclusive.
|
||||
*/
|
||||
private static class Range {
|
||||
|
||||
private final Integer min;
|
||||
|
||||
private final Integer max;
|
||||
|
||||
Range(Integer min, Integer max) {
|
||||
this.min = min;
|
||||
this.max = max;
|
||||
}
|
||||
|
||||
Integer getMin() {
|
||||
return min;
|
||||
}
|
||||
|
||||
Integer getMax() {
|
||||
return max;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o)
|
||||
return true;
|
||||
if (o == null || getClass() != o.getClass())
|
||||
return false;
|
||||
Range range = (Range) o;
|
||||
return Objects.equals(getMin(), range.getMin()) && Objects.equals(getMax(), range.getMax());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(getMin(), getMax());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Range{" + "min=" + min + ", max=" + max + '}';
|
||||
}
|
||||
}
|
||||
}
|
|
@ -124,11 +124,44 @@ public class Java8SortUnitTest {
|
|||
|
||||
@Test
|
||||
public final void givenStreamCustomOrdering_whenSortingEntitiesByName_thenCorrectlySorted() {
|
||||
|
||||
final List<Human> humans = Lists.newArrayList(new Human("Sarah", 10), new Human("Jack", 12));
|
||||
final Comparator<Human> nameComparator = (h1, h2) -> h1.getName().compareTo(h2.getName());
|
||||
|
||||
final List<Human> sortedHumans = humans.stream().sorted(nameComparator).collect(Collectors.toList());
|
||||
Assert.assertThat(sortedHumans.get(0), equalTo(new Human("Jack", 12)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void givenStreamComparatorOrdering_whenSortingEntitiesByName_thenCorrectlySorted() {
|
||||
final List<Human> humans = Lists.newArrayList(new Human("Sarah", 10), new Human("Jack", 12));
|
||||
|
||||
final List<Human> sortedHumans = humans.stream().sorted(Comparator.comparing(Human::getName)).collect(Collectors.toList());
|
||||
Assert.assertThat(sortedHumans.get(0), equalTo(new Human("Jack", 12)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void givenStreamNaturalOrdering_whenSortingEntitiesByNameReversed_thenCorrectlySorted() {
|
||||
final List<String> letters = Lists.newArrayList("B", "A", "C");
|
||||
|
||||
final List<String> reverseSortedLetters = letters.stream().sorted(Comparator.reverseOrder()).collect(Collectors.toList());
|
||||
Assert.assertThat(reverseSortedLetters.get(0), equalTo("C"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void givenStreamCustomOrdering_whenSortingEntitiesByNameReversed_thenCorrectlySorted() {
|
||||
final List<Human> humans = Lists.newArrayList(new Human("Sarah", 10), new Human("Jack", 12));
|
||||
final Comparator<Human> reverseNameComparator = (h1, h2) -> h2.getName().compareTo(h1.getName());
|
||||
|
||||
final List<Human> reverseSortedHumans = humans.stream().sorted(reverseNameComparator).collect(Collectors.toList());
|
||||
Assert.assertThat(reverseSortedHumans.get(0), equalTo(new Human("Sarah", 10)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void givenStreamComparatorOrdering_whenSortingEntitiesByNameReversed_thenCorrectlySorted() {
|
||||
final List<Human> humans = Lists.newArrayList(new Human("Sarah", 10), new Human("Jack", 12));
|
||||
|
||||
final List<Human> reverseSortedHumans = humans.stream().sorted(Comparator.comparing(Human::getName, Comparator.reverseOrder())).collect(Collectors.toList());
|
||||
Assert.assertThat(reverseSortedHumans.get(0), equalTo(new Human("Sarah", 10)));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
package com.baeldung.socket.read;
|
||||
|
||||
import java.net.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.io.*;
|
||||
|
||||
public class Client {
|
||||
|
||||
public void runClient(String ip, int port) {
|
||||
try {
|
||||
Socket socket = new Socket(ip, port);
|
||||
System.out.println("Connected to server ...");
|
||||
DataInputStream in = new DataInputStream(System.in);
|
||||
DataOutputStream out = new DataOutputStream(socket.getOutputStream());
|
||||
|
||||
char type = 's'; // s for string
|
||||
int length = 29;
|
||||
String data = "This is a string of length 29";
|
||||
byte[] dataInBytes = data.getBytes(StandardCharsets.UTF_8);
|
||||
//Sending data in TLV format
|
||||
out.writeChar(type);
|
||||
out.writeInt(length);
|
||||
out.write(dataInBytes);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
package com.baeldung.socket.read;
|
||||
|
||||
import java.net.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.io.*;
|
||||
|
||||
public class Server {
|
||||
|
||||
public void runServer(int port) {
|
||||
//Start the server and wait for connection
|
||||
try {
|
||||
ServerSocket server = new ServerSocket(port);
|
||||
System.out.println("Server Started. Waiting for connection ...");
|
||||
Socket socket = server.accept();
|
||||
System.out.println("Got connection from client.");
|
||||
//Get input stream from socket variable and convert the same to DataInputStream
|
||||
DataInputStream in = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
|
||||
//Read type and length of data
|
||||
char dataType = in.readChar();
|
||||
int length = in.readInt();
|
||||
System.out.println("Type : "+dataType);
|
||||
System.out.println("Lenght :"+length);
|
||||
if(dataType == 's') {
|
||||
//Read String data in bytes
|
||||
byte[] messageByte = new byte[length];
|
||||
boolean end = false;
|
||||
StringBuilder dataString = new StringBuilder(length);
|
||||
int totalBytesRead = 0;
|
||||
//We need to run while loop, to read all data in that stream
|
||||
while(!end) {
|
||||
int currentBytesRead = in.read(messageByte);
|
||||
totalBytesRead = currentBytesRead + totalBytesRead;
|
||||
if(totalBytesRead <= length) {
|
||||
dataString.append(new String(messageByte,0,currentBytesRead,StandardCharsets.UTF_8));
|
||||
} else {
|
||||
dataString.append(new String(messageByte,0,length - totalBytesRead + currentBytesRead,StandardCharsets.UTF_8));
|
||||
}
|
||||
if(dataString.length()>=length) {
|
||||
end = true;
|
||||
}
|
||||
}
|
||||
System.out.println("Read "+length+" bytes of message from client. Message = "+dataString);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
package com.baeldung.socket.read;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class SocketReadAllDataLiveTest {
|
||||
|
||||
@Test
|
||||
public void givenServerAndClient_whenClientSendsAndServerReceivesData_thenCorrect() {
|
||||
//Run server in new thread
|
||||
Runnable runnable1 = () -> { runServer(); };
|
||||
Thread thread1 = new Thread(runnable1);
|
||||
thread1.start();
|
||||
//Wait for 10 seconds
|
||||
try {
|
||||
TimeUnit.SECONDS.sleep(10);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
//Run client in a new thread
|
||||
Runnable runnable2 = () -> { runClient(); };
|
||||
Thread thread2 = new Thread(runnable2);
|
||||
thread2.start();
|
||||
}
|
||||
|
||||
public static void runServer() {
|
||||
//Run Server
|
||||
Server server = new Server();
|
||||
server.runServer(5555);
|
||||
}
|
||||
|
||||
public static void runClient() {
|
||||
//Run Client
|
||||
Client client = new Client();
|
||||
client.runClient("127.0.0.1", 5555);
|
||||
}
|
||||
}
|
|
@ -2,3 +2,5 @@
|
|||
|
||||
- [Void Type in Kotlin](https://www.baeldung.com/kotlin-void-type)
|
||||
- [How to use Kotlin Range Expressions](https://www.baeldung.com/kotlin-ranges)
|
||||
- [Split a List into Parts in Kotlin](https://www.baeldung.com/kotlin-split-list-into-parts)
|
||||
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
package com.baeldung.scope
|
||||
|
||||
data class Student(var studentId: String = "", var name: String = "", var surname: String = "") {
|
||||
}
|
||||
|
||||
data class Teacher(var teacherId: Int = 0, var name: String = "", var surname: String = "") {
|
||||
fun setId(anId: Int): Teacher = apply { teacherId = anId }
|
||||
fun setName(aName: String): Teacher = apply { name = aName }
|
||||
fun setSurname(aSurname: String): Teacher = apply { surname = aSurname }
|
||||
}
|
||||
|
||||
data class Headers(val headerInfo: String)
|
||||
|
||||
data class Response(val headers: Headers)
|
||||
|
||||
data class RestClient(val url: String) {
|
||||
fun getResponse() = Response(Headers("some header info"))
|
||||
}
|
||||
|
||||
data class BankAccount(val id: Int) {
|
||||
fun checkAuthorization(username: String) = Unit
|
||||
fun addPayee(payee: String) = Unit
|
||||
fun makePayment(paymentDetails: String) = Unit
|
||||
|
||||
}
|
|
@ -4,7 +4,7 @@ import org.junit.Test
|
|||
import kotlin.test.assertTrue
|
||||
import kotlin.test.assertFalse
|
||||
|
||||
class ValidationUnitTest {
|
||||
class ValidationTest {
|
||||
|
||||
@Test
|
||||
fun whenAmountIsOneAndNameIsAlice_thenTrue() {
|
||||
|
|
|
@ -1,42 +0,0 @@
|
|||
package com.baeldung.annotations
|
||||
|
||||
import org.junit.jupiter.api.Assertions.assertTrue
|
||||
import org.junit.jupiter.api.Assertions.assertFalse
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
|
||||
class ValidationUnitTest {
|
||||
|
||||
@Test
|
||||
fun whenAmountIsOneAndNameIsAlice_thenTrue() {
|
||||
assertTrue(Validator().isValid(Item(1f, "Alice")))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun whenAmountIsOneAndNameIsBob_thenTrue() {
|
||||
assertTrue(Validator().isValid(Item(1f, "Bob")))
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
fun whenAmountIsMinusOneAndNameIsAlice_thenFalse() {
|
||||
assertFalse(Validator().isValid(Item(-1f, "Alice")))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun whenAmountIsMinusOneAndNameIsBob_thenFalse() {
|
||||
assertFalse(Validator().isValid(Item(-1f, "Bob")))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun whenAmountIsOneAndNameIsTom_thenFalse() {
|
||||
assertFalse(Validator().isValid(Item(1f, "Tom")))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun whenAmountIsMinusOneAndNameIsTom_thenFalse() {
|
||||
assertFalse(Validator().isValid(Item(-1f, "Tom")))
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,143 @@
|
|||
package com.baeldung.scope
|
||||
|
||||
import org.junit.Test
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
|
||||
class ScopeFunctionsUnitTest {
|
||||
|
||||
class Logger {
|
||||
|
||||
var called : Boolean = false
|
||||
|
||||
fun info(message: String) {
|
||||
called = true
|
||||
}
|
||||
|
||||
fun wasCalled() = called
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldTransformWhenLetFunctionUsed() {
|
||||
val stringBuider = StringBuilder()
|
||||
val numberOfCharacters = stringBuider.let {
|
||||
it.append("This is a transformation function.")
|
||||
it.append("It takes a StringBuilder instance and returns the number of characters in the generated String")
|
||||
it.length
|
||||
}
|
||||
|
||||
assertTrue {
|
||||
numberOfCharacters == 128
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldHandleNullabilityWhenLetFunctionUsed() {
|
||||
|
||||
val message: String? = "hello there!"
|
||||
val charactersInMessage = message?.let {
|
||||
"At this point is safe to reference the variable. Let's print the message: $it"
|
||||
} ?: "default value"
|
||||
|
||||
assertTrue {
|
||||
charactersInMessage.equals("At this point is safe to reference the variable. Let's print the message: hello there!")
|
||||
}
|
||||
|
||||
val aNullMessage = null
|
||||
val thisIsNull = aNullMessage?.let {
|
||||
"At this point it would be safe to reference the variable. But it will not really happen because it is null. Let's reference: $it"
|
||||
} ?: "default value"
|
||||
|
||||
assertTrue {
|
||||
thisIsNull.equals("default value")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldInitializeObjectWhenUsingApply() {
|
||||
val aStudent = Student().apply {
|
||||
studentId = "1234567"
|
||||
name = "Mary"
|
||||
surname = "Smith"
|
||||
}
|
||||
|
||||
assertTrue {
|
||||
aStudent.name.equals("Mary")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldAllowBuilderStyleObjectDesignWhenApplyUsedInClassMethods() {
|
||||
val teacher = Teacher()
|
||||
.setId(1000)
|
||||
.setName("Martha")
|
||||
.setSurname("Spector")
|
||||
|
||||
assertTrue {
|
||||
teacher.surname.equals("Spector")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldAllowSideEffectWhenUsingAlso() {
|
||||
val restClient = RestClient("http://www.someurl.com")
|
||||
|
||||
val logger = Logger()
|
||||
|
||||
val headers = restClient
|
||||
.getResponse()
|
||||
.also { logger.info(it.toString()) }
|
||||
.headers
|
||||
|
||||
assertTrue {
|
||||
logger.wasCalled() && headers.headerInfo.equals("some header info")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldInitializeFieldWhenAlsoUsed() {
|
||||
val aStudent = Student().also { it.name = "John"}
|
||||
|
||||
assertTrue {
|
||||
aStudent.name.equals("John")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldLogicallyGroupObjectCallsWhenUsingWith() {
|
||||
val bankAccount = BankAccount(1000)
|
||||
with (bankAccount) {
|
||||
checkAuthorization("someone")
|
||||
addPayee("some payee")
|
||||
makePayment("payment information")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldConvertObjectWhenRunUsed() {
|
||||
val stringBuider = StringBuilder()
|
||||
val numberOfCharacters = stringBuider.run {
|
||||
append("This is a transformation function.")
|
||||
append("It takes a StringBuilder instance and returns the number of characters in the generated String")
|
||||
length
|
||||
}
|
||||
|
||||
assertTrue {
|
||||
numberOfCharacters == 128
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldHandleNullabilityWhenRunIsUsed() {
|
||||
val message: String? = "hello there!"
|
||||
val charactersInMessage = message?.run {
|
||||
"At this point is safe to reference the variable. Let's print the message: $this"
|
||||
} ?: "default value"
|
||||
|
||||
assertTrue {
|
||||
charactersInMessage.equals("At this point is safe to reference the variable. Let's print the message: hello there!")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -11,3 +11,5 @@
|
|||
- [Convert JSON to a Map Using Gson](https://www.baeldung.com/gson-json-to-map)
|
||||
- [Working with Primitive Values in Gson](https://www.baeldung.com/java-gson-primitives)
|
||||
- [Convert String to JsonObject with Gson](https://www.baeldung.com/gson-string-to-jsonobject)
|
||||
- [Mapping Multiple JSON Fields to One Java Field](https://www.baeldung.com/json-multiple-fields-single-java-field)
|
||||
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
*.class
|
||||
|
||||
#folders#
|
||||
/target
|
||||
/neoDb*
|
||||
/data
|
||||
/src/main/webapp/WEB-INF/classes
|
||||
*/META-INF/*
|
||||
|
||||
# Packaged files #
|
||||
*.jar
|
||||
*.war
|
||||
*.ear
|
|
@ -0,0 +1,9 @@
|
|||
=========
|
||||
|
||||
## Jackson Cookbooks and Examples
|
||||
|
||||
###The Course
|
||||
The "REST With Spring" Classes: http://bit.ly/restwithspring
|
||||
|
||||
### Relevant Articles:
|
||||
- [Mapping Multiple JSON Fields to One Java Field](https://www.baeldung.com/json-multiple-fields-single-java-field)
|
|
@ -0,0 +1,52 @@
|
|||
<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>jackson-2</artifactId>
|
||||
<version>0.1-SNAPSHOT</version>
|
||||
<name>jackson-2</name>
|
||||
|
||||
<parent>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>parent-java</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<relativePath>../parent-java</relativePath>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<!-- marshalling -->
|
||||
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<version>${jackson.version}</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- test scoped -->
|
||||
|
||||
<dependency>
|
||||
<groupId>org.assertj</groupId>
|
||||
<artifactId>assertj-core</artifactId>
|
||||
<version>${assertj.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<finalName>jackson-2</finalName>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
<filtering>true</filtering>
|
||||
</resource>
|
||||
</resources>
|
||||
</build>
|
||||
|
||||
<properties>
|
||||
|
||||
<!-- testing -->
|
||||
<assertj.version>3.11.0</assertj.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,13 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
|
||||
</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<root level="INFO">
|
||||
<appender-ref ref="STDOUT" />
|
||||
</root>
|
||||
</configuration>
|
|
@ -0,0 +1,29 @@
|
|||
*.class
|
||||
|
||||
0.*
|
||||
|
||||
#folders#
|
||||
/target
|
||||
/neoDb*
|
||||
/data
|
||||
/src/main/webapp/WEB-INF/classes
|
||||
*/META-INF/*
|
||||
.resourceCache
|
||||
|
||||
# Packaged files #
|
||||
*.jar
|
||||
*.war
|
||||
*.ear
|
||||
|
||||
# Files generated by integration tests
|
||||
*.txt
|
||||
backup-pom.xml
|
||||
/bin/
|
||||
/temp
|
||||
|
||||
#IntelliJ specific
|
||||
.idea/
|
||||
*.iml
|
||||
|
||||
#jenv
|
||||
.java-version
|
|
@ -0,0 +1,55 @@
|
|||
<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>java-dates-2</artifactId>
|
||||
<version>0.1.0-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
<name>java-dates-2</name>
|
||||
|
||||
<parent>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>parent-java</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<relativePath>../parent-java</relativePath>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
<!-- test scoped -->
|
||||
<dependency>
|
||||
<groupId>org.assertj</groupId>
|
||||
<artifactId>assertj-core</artifactId>
|
||||
<version>${assertj.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<finalName>java-dates-2</finalName>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
<filtering>true</filtering>
|
||||
</resource>
|
||||
</resources>
|
||||
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>${maven-compiler-plugin.version}</version>
|
||||
<configuration>
|
||||
<source>${maven.compiler.source}</source>
|
||||
<target>${maven.compiler.target}</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<properties>
|
||||
<!-- testing -->
|
||||
<assertj.version>3.6.1</assertj.version>
|
||||
<maven.compiler.source>1.9</maven.compiler.source>
|
||||
<maven.compiler.target>1.9</maven.compiler.target>
|
||||
</properties>
|
||||
</project>
|
|
@ -0,0 +1,36 @@
|
|||
package com.baeldung.xmlgregoriancalendar;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import javax.xml.datatype.DatatypeConfigurationException;
|
||||
import javax.xml.datatype.DatatypeConstants;
|
||||
import javax.xml.datatype.DatatypeFactory;
|
||||
import javax.xml.datatype.XMLGregorianCalendar;
|
||||
import java.time.LocalDate;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class XmlGregorianCalendarConverterUnitTest {
|
||||
|
||||
@Test
|
||||
public void fromLocalDateToXMLGregorianCalendar() throws DatatypeConfigurationException {
|
||||
LocalDate localDate = LocalDate.of(2017, 4, 25);
|
||||
XMLGregorianCalendar xmlGregorianCalendar = DatatypeFactory.newInstance().newXMLGregorianCalendar(localDate.toString());
|
||||
|
||||
assertThat(xmlGregorianCalendar.getYear()).isEqualTo(localDate.getYear());
|
||||
assertThat(xmlGregorianCalendar.getMonth()).isEqualTo(localDate.getMonthValue());
|
||||
assertThat(xmlGregorianCalendar.getDay()).isEqualTo(localDate.getDayOfMonth());
|
||||
assertThat(xmlGregorianCalendar.getTimezone()).isEqualTo(DatatypeConstants.FIELD_UNDEFINED);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fromXMLGregorianCalendarToLocalDate() throws DatatypeConfigurationException {
|
||||
XMLGregorianCalendar xmlGregorianCalendar = DatatypeFactory.newInstance().newXMLGregorianCalendar("2017-04-25");
|
||||
LocalDate localDate = LocalDate.of(xmlGregorianCalendar.getYear(), xmlGregorianCalendar.getMonth(), xmlGregorianCalendar.getDay());
|
||||
|
||||
assertThat(localDate.getYear()).isEqualTo(xmlGregorianCalendar.getYear());
|
||||
assertThat(localDate.getMonthValue()).isEqualTo(xmlGregorianCalendar.getMonth());
|
||||
assertThat(localDate.getDayOfMonth()).isEqualTo(xmlGregorianCalendar.getDay());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
### Relevant Articles:
|
||||
- [Guide to Stream.reduce()](https://www.baeldung.com/java-stream-reduce)
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
package com.baeldung.filters;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.FilterConfig;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.annotation.WebFilter;
|
||||
import java.io.IOException;
|
||||
|
||||
@WebFilter(urlPatterns = "/uppercase")
|
||||
public class EmptyParamFilter implements Filter {
|
||||
|
||||
@Override
|
||||
public void init(FilterConfig filterConfig) throws ServletException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
|
||||
FilterChain filterChain) throws IOException, ServletException {
|
||||
String inputString = servletRequest.getParameter("input");
|
||||
|
||||
if (inputString != null && inputString.matches("[A-Za-z0-9]+")) {
|
||||
filterChain.doFilter(servletRequest, servletResponse);
|
||||
} else {
|
||||
servletResponse.getWriter().println("Missing input parameter");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package com.baeldung.listeners;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletContextEvent;
|
||||
import javax.servlet.ServletContextListener;
|
||||
import javax.servlet.annotation.WebListener;
|
||||
|
||||
@WebListener
|
||||
public class AppListener implements ServletContextListener {
|
||||
|
||||
@Override
|
||||
public void contextInitialized(ServletContextEvent event) {
|
||||
ServletContext context = event.getServletContext();
|
||||
context.setAttribute("counter", 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void contextDestroyed(ServletContextEvent event) {
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package com.baeldung.listeners;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletRequestEvent;
|
||||
import javax.servlet.ServletRequestListener;
|
||||
import javax.servlet.annotation.WebListener;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
@WebListener
|
||||
public class RequestListener implements ServletRequestListener {
|
||||
|
||||
@Override
|
||||
public void requestInitialized(ServletRequestEvent event) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestDestroyed(ServletRequestEvent event) {
|
||||
HttpServletRequest request = (HttpServletRequest)event.getServletRequest();
|
||||
if (!request.getServletPath().equals("/counter")) {
|
||||
ServletContext context = event.getServletContext();
|
||||
context.setAttribute("counter", (int)context.getAttribute("counter") + 1);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package com.baeldung.servlets;
|
||||
|
||||
import javax.servlet.annotation.WebServlet;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
|
||||
@WebServlet(urlPatterns = "/counter", name = "counterServlet")
|
||||
public class CounterServlet extends HttpServlet {
|
||||
|
||||
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
|
||||
PrintWriter out = response.getWriter();
|
||||
|
||||
int count = (int)request.getServletContext().getAttribute("counter");
|
||||
|
||||
out.println("Request counter: " + count);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package com.baeldung.servlets;
|
||||
|
||||
import javax.servlet.annotation.WebServlet;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
|
||||
@WebServlet(urlPatterns = "/uppercase", name = "uppercaseServlet")
|
||||
public class UppercaseServlet extends HttpServlet {
|
||||
|
||||
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
|
||||
String inputString = request.getParameter("input").toUpperCase();
|
||||
|
||||
PrintWriter out = response.getWriter();
|
||||
|
||||
out.println(inputString);
|
||||
}
|
||||
}
|
|
@ -19,6 +19,14 @@
|
|||
<name>exposed</name>
|
||||
<url>https://dl.bintray.com/kotlin/exposed</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
<id>kotlinx</id>
|
||||
<name>bintray</name>
|
||||
<url>https://dl.bintray.com/kotlin/kotlinx</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<dependencies>
|
||||
|
@ -112,9 +120,30 @@
|
|||
<version>3.3.0</version>
|
||||
<type>pom</type>
|
||||
</dependency>
|
||||
|
||||
<!-- https://mvnrepository.com/artifact/junit/junit -->
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>${junit.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<version>27.1-jre</version>
|
||||
</dependency>
|
||||
<!-- https://mvnrepository.com/artifact/org.jetbrains.kotlinx/kotlinx-collections-immutable -->
|
||||
<dependency>
|
||||
<groupId>org.jetbrains.kotlinx</groupId>
|
||||
<artifactId>kotlinx-collections-immutable</artifactId>
|
||||
<version>0.1</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<properties>
|
||||
<junit.version>4.12</junit.version>
|
||||
<mockito-kotlin.version>1.5.0</mockito-kotlin.version>
|
||||
<kodein.version>4.1.0</kodein.version>
|
||||
<klaxon.version>3.0.4</klaxon.version>
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
package com.baeldung.kotlin.immutable
|
||||
|
||||
import junit.framework.Assert.assertEquals
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.immutableListOf
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.rules.ExpectedException
|
||||
|
||||
class KotlinxImmutablesUnitTest{
|
||||
|
||||
|
||||
@Rule
|
||||
@JvmField
|
||||
var ee : ExpectedException = ExpectedException.none()
|
||||
|
||||
@Test
|
||||
fun givenKICLList_whenAddTried_checkExceptionThrown(){
|
||||
|
||||
val list: ImmutableList<String> = immutableListOf("I", "am", "immutable")
|
||||
|
||||
list.add("My new item")
|
||||
|
||||
assertEquals(listOf("I", "am", "immutable"), list)
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
package com.baeldung.kotlin.immutable
|
||||
|
||||
import com.google.common.collect.ImmutableList
|
||||
import com.google.common.collect.ImmutableSet
|
||||
import junit.framework.Assert.assertEquals
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.rules.ExpectedException
|
||||
|
||||
class ReadOnlyUnitTest{
|
||||
|
||||
@Test
|
||||
fun givenReadOnlyList_whenCastToMutableList_checkNewElementsAdded(){
|
||||
|
||||
val list: List<String> = listOf("This", "Is", "Totally", "Immutable")
|
||||
|
||||
(list as MutableList<String>)[2] = "Not"
|
||||
|
||||
assertEquals(listOf("This", "Is", "Not", "Immutable"), list)
|
||||
|
||||
}
|
||||
|
||||
@Rule
|
||||
@JvmField
|
||||
var ee : ExpectedException = ExpectedException.none()
|
||||
|
||||
@Test
|
||||
fun givenImmutableList_whenAddTried_checkExceptionThrown(){
|
||||
|
||||
val list: List<String> = ImmutableList.of("I", "am", "actually", "immutable")
|
||||
|
||||
ee.expect(UnsupportedOperationException::class.java)
|
||||
|
||||
(list as MutableList<String>).add("Oops")
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
fun givenMutableList_whenCopiedAndAddTried_checkExceptionThrown(){
|
||||
|
||||
val mutableList : List<String> = listOf("I", "Am", "Definitely", "Immutable")
|
||||
|
||||
(mutableList as MutableList<String>)[2] = "100% Not"
|
||||
|
||||
assertEquals(listOf("I", "Am", "100% Not", "Immutable"), mutableList)
|
||||
|
||||
val list: List<String> = ImmutableList.copyOf(mutableList)
|
||||
|
||||
ee.expect(UnsupportedOperationException::class.java)
|
||||
|
||||
(list as MutableList<String>)[2] = "Really?"
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
fun givenImmutableSetBuilder_whenAddTried_checkExceptionThrown(){
|
||||
|
||||
val mutableList : List<String> = listOf("Hello", "Baeldung")
|
||||
val set: ImmutableSet<String> = ImmutableSet.builder<String>()
|
||||
.add("I","am","immutable")
|
||||
.addAll(mutableList)
|
||||
.build()
|
||||
|
||||
assertEquals(setOf("Hello", "Baeldung", "I", "am", "immutable"), set)
|
||||
|
||||
ee.expect(UnsupportedOperationException::class.java)
|
||||
|
||||
(set as MutableSet<String>).add("Oops")
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -83,13 +83,18 @@
|
|||
<artifactId>jmh-generator-annprocess</artifactId>
|
||||
<version>${openjdk-jmh.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.xml.bind</groupId>
|
||||
<artifactId>jaxb-api</artifactId>
|
||||
<version>2.3.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<finalName>hibernate5</finalName>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
<directory>src/test/resources</directory>
|
||||
<filtering>true</filtering>
|
||||
</resource>
|
||||
</resources>
|
||||
|
|
|
@ -113,6 +113,7 @@ public class HibernateUtil {
|
|||
metadataSources.addAnnotatedClass(OptimisticLockingCourse.class);
|
||||
metadataSources.addAnnotatedClass(OptimisticLockingStudent.class);
|
||||
metadataSources.addAnnotatedClass(OfficeEmployee.class);
|
||||
metadataSources.addAnnotatedClass(Post.class);
|
||||
|
||||
Metadata metadata = metadataSources.getMetadataBuilder()
|
||||
.applyBasicType(LocalDateStringType.INSTANCE)
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
package com.baeldung.hibernate.pojo;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
|
||||
@Entity
|
||||
@Table(name = "posts")
|
||||
public class Post {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private int id;
|
||||
|
||||
private String title;
|
||||
|
||||
private String body;
|
||||
|
||||
public Post() { }
|
||||
|
||||
public Post(String title, String body) {
|
||||
this.title = title;
|
||||
this.body = body;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(int 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 String toString() {
|
||||
return "Post{" +
|
||||
"id=" + id +
|
||||
", title='" + title + '\'' +
|
||||
", body='" + body + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package com.baeldung.hibernate.transaction;
|
||||
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.Transaction;
|
||||
import org.hibernate.query.Query;
|
||||
|
||||
public class PostService {
|
||||
|
||||
|
||||
private Session session;
|
||||
|
||||
public PostService(Session session) {
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
|
||||
public void updatePost(String title, String body, int id) {
|
||||
Transaction txn = session.beginTransaction();
|
||||
Query updateQuery = session.createQuery("UPDATE Post p SET p.title = ?1, p.body = ?2 WHERE p.id = ?3");
|
||||
updateQuery.setParameter(1, title);
|
||||
updateQuery.setParameter(2, body);
|
||||
updateQuery.setParameter(3, id);
|
||||
updateQuery.executeUpdate();
|
||||
txn.commit();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -74,4 +74,6 @@ public class CustomClassIntegrationTest {
|
|||
assertEquals("John Smith", result.getEmployeeName());
|
||||
assertEquals("Sales", result.getDepartmentName());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
package com.baeldung.hibernate.transaction;
|
||||
|
||||
import com.baeldung.hibernate.HibernateUtil;
|
||||
import com.baeldung.hibernate.pojo.Post;
|
||||
import com.baeldung.hibernate.transaction.PostService;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.SessionFactory;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Properties;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class TransactionIntegrationTest {
|
||||
|
||||
private static PostService postService;
|
||||
private static Session session;
|
||||
private static Logger logger = LoggerFactory.getLogger(TransactionIntegrationTest.class);
|
||||
|
||||
@BeforeClass
|
||||
public static void init() throws IOException {
|
||||
Properties properties = new Properties();
|
||||
properties.setProperty("hibernate.connection.driver_class", "org.h2.Driver");
|
||||
properties.setProperty("hibernate.connection.url", "jdbc:h2:mem:mydb1;DB_CLOSE_DELAY=-1");
|
||||
properties.setProperty("hibernate.connection.username", "sa");
|
||||
properties.setProperty("hibernate.show_sql", "true");
|
||||
properties.setProperty("jdbc.password", "");
|
||||
properties.setProperty("hibernate.dialect", "org.hibernate.dialect.H2Dialect");
|
||||
properties.setProperty("hibernate.hbm2ddl.auto", "create-drop");
|
||||
SessionFactory sessionFactory = HibernateUtil.getSessionFactoryByProperties(properties);
|
||||
session = sessionFactory.openSession();
|
||||
postService = new PostService(session);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenTitleAndBody_whenRepositoryUpdatePost_thenUpdatePost() {
|
||||
|
||||
Post post = new Post("This is a title", "This is a sample post");
|
||||
session.persist(post);
|
||||
|
||||
String title = "[UPDATE] Java HowTos";
|
||||
String body = "This is an updated posts on Java how-tos";
|
||||
postService.updatePost(title, body, post.getId());
|
||||
|
||||
session.refresh(post);
|
||||
|
||||
assertEquals(post.getTitle(), title);
|
||||
assertEquals(post.getBody(), body);
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -7,3 +7,4 @@
|
|||
- [Hibernate Field Naming with Spring Boot](https://www.baeldung.com/hibernate-field-naming-spring-boot)
|
||||
- [Integrating Spring Boot with HSQLDB](https://www.baeldung.com/spring-boot-hsqldb)
|
||||
- [Configuring a DataSource Programmatically in Spring Boot](https://www.baeldung.com/spring-boot-configure-data-source-programmatic)
|
||||
- [Resolving “Failed to Configure a DataSource” Error](https://www.baeldung.com/spring-boot-failed-to-configure-data-source)
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
=========
|
||||
|
||||
## Spring Data JPA Example Project
|
||||
|
||||
### Relevant Articles:
|
|
@ -0,0 +1,30 @@
|
|||
<?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-data-jpa-2</artifactId>
|
||||
<name>spring-data-jpa</name>
|
||||
|
||||
<parent>
|
||||
<artifactId>parent-boot-2</artifactId>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<relativePath>../../parent-boot-2</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>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,13 @@
|
|||
package com.baeldung;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class Application {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(Application.class, args);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
package com.baeldung.entity;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
|
||||
@Entity
|
||||
public class Fruit {
|
||||
|
||||
@Id
|
||||
private long id;
|
||||
private String name;
|
||||
private String color;
|
||||
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getColor() {
|
||||
return color;
|
||||
}
|
||||
|
||||
public void setColor(String color) {
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package com.baeldung.repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Modifying;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import com.baeldung.entity.Fruit;
|
||||
|
||||
@Repository
|
||||
public interface FruitRepository extends JpaRepository<Fruit, Long> {
|
||||
|
||||
Long deleteByName(String name);
|
||||
|
||||
List<Fruit> deleteByColor(String color);
|
||||
|
||||
Long removeByName(String name);
|
||||
|
||||
List<Fruit> removeByColor(String color);
|
||||
|
||||
@Modifying
|
||||
@Query("delete from Fruit f where f.name=:name or f.color=:color")
|
||||
List<Fruit> deleteFruits(@Param("name") String name, @Param("color") String color);
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
spring.jpa.show-sql=true
|
|
@ -0,0 +1,77 @@
|
|||
package com.baeldung.repository;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.jupiter.api.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.jdbc.Sql;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import com.baeldung.entity.Fruit;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest
|
||||
class FruitRepositoryIntegrationTest {
|
||||
|
||||
@Autowired
|
||||
private FruitRepository fruitRepository;
|
||||
|
||||
@Transactional
|
||||
@Test
|
||||
@Sql(scripts = { "/test-fruit-data.sql" })
|
||||
public void givenFruits_WhenDeletedByColor_ThenDeletedFruitsShouldReturn() {
|
||||
|
||||
List<Fruit> fruits = fruitRepository.deleteByColor("green");
|
||||
|
||||
assertEquals("number of fruits are not matching", 2, fruits.size());
|
||||
fruits.forEach(fruit -> assertEquals("Its not a green fruit", "green", fruit.getColor()));
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Test
|
||||
@Sql(scripts = { "/test-fruit-data.sql" })
|
||||
public void givenFruits_WhenDeletedByName_ThenDeletedFruitCountShouldReturn() {
|
||||
|
||||
Long deletedFruitCount = fruitRepository.deleteByName("apple");
|
||||
|
||||
assertEquals("deleted fruit count is not matching", 1, deletedFruitCount.intValue());
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Test
|
||||
@Sql(scripts = { "/test-fruit-data.sql" })
|
||||
public void givenFruits_WhenRemovedByColor_ThenDeletedFruitsShouldReturn() {
|
||||
|
||||
List<Fruit> fruits = fruitRepository.removeByColor("green");
|
||||
|
||||
assertEquals("number of fruits are not matching", 2, fruits.size());
|
||||
fruits.forEach(fruit -> assertEquals("Its not a green fruit", "green", fruit.getColor()));
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Test
|
||||
@Sql(scripts = { "/test-fruit-data.sql" })
|
||||
public void givenFruits_WhenRemovedByName_ThenDeletedFruitCountShouldReturn() {
|
||||
|
||||
Long deletedFruitCount = fruitRepository.removeByName("apple");
|
||||
|
||||
assertEquals("deleted fruit count is not matching", 1, deletedFruitCount.intValue());
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Test
|
||||
@Sql(scripts = { "/test-fruit-data.sql" })
|
||||
public void givenFruits_WhenDeletedByColorOrName_ThenDeletedFruitsShouldReturn() {
|
||||
|
||||
List<Fruit> fruits = fruitRepository.deleteFruits("apple", "green");
|
||||
|
||||
assertEquals("number of fruits are not matching", 3, fruits.size());
|
||||
fruits.forEach(fruit -> assertTrue("Its not a green fruit or apple", ("green".equals(fruit.getColor())) || "apple".equals(fruit.getColor())));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
insert into fruit(id,name,color) values (1,'apple','red');
|
||||
insert into fruit(id,name,color) values (2,'custard apple','green');
|
||||
insert into fruit(id,name,color) values (3,'mango','yellow');
|
||||
insert into fruit(id,name,color) values (4,'guava','green');
|
5
pom.xml
5
pom.xml
|
@ -377,6 +377,7 @@
|
|||
<module>core-groovy</module>
|
||||
<!-- <module>core-java-10</module> --> <!-- We haven't upgraded to java 10. Fixing in BAEL-10841 -->
|
||||
<!-- <module>core-java-11</module> --> <!-- We haven't upgraded to java 11. Fixing in BAEL-10841 -->
|
||||
<!-- <module>core-java-12</module> --> <!-- We haven't upgraded to java 12. Fixing in BAEL-10841 -->
|
||||
<module>core-java-8</module>
|
||||
<!--<module>core-java-9</module> --> <!-- We haven't upgraded to java 9. Fixing in BAEL-10841 -->
|
||||
<!--<module>core-java-os</module> --> <!-- We haven't upgraded to java 9.-->
|
||||
|
@ -436,9 +437,11 @@
|
|||
<module>immutables</module>
|
||||
|
||||
<module>jackson</module>
|
||||
<module>jackson-2</module>
|
||||
<module>java-collections-conversions</module>
|
||||
<module>java-collections-maps</module>
|
||||
<!-- <module>java-dates</module> --> <!-- We haven't upgraded to java 9. Fixing in BAEL-10841 -->
|
||||
<!-- <module>java-dates-2</module> --> <!-- We haven't upgraded to java 9. Fixing in BAEL-10841 -->
|
||||
<!-- <module>java-ee-8-security-api</module> --> <!-- long running -->
|
||||
<module>java-lite</module>
|
||||
<module>java-numbers</module>
|
||||
|
@ -579,6 +582,7 @@
|
|||
<module>spring-5-reactive-client</module>
|
||||
<module>spring-5-reactive-oauth</module>
|
||||
<module>spring-5-reactive-security</module>
|
||||
<module>spring-5-reactive-netty</module>
|
||||
<module>spring-5-security</module>
|
||||
<module>spring-5-security-oauth</module>
|
||||
|
||||
|
@ -1078,6 +1082,7 @@
|
|||
<module>immutables</module>
|
||||
|
||||
<module>jackson</module>
|
||||
<module>jackson-2</module>
|
||||
<module>java-collections-conversions</module>
|
||||
<module>java-collections-maps</module>
|
||||
<!-- <module>java-dates</module> --> <!-- We haven't upgraded to java 9. Fixing in BAEL-10841 -->
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
# Folders #
|
||||
**/.idea
|
||||
**/target
|
||||
|
||||
# Files #
|
||||
*.log
|
||||
|
||||
# Packaged files #
|
||||
*.jar
|
||||
*.war
|
||||
*.ear
|
|
@ -0,0 +1,3 @@
|
|||
## Spring 5 Reactive Project With Netty Server
|
||||
|
||||
Includes configuration options for Netty server.
|
|
@ -0,0 +1,51 @@
|
|||
<?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-5-reactive-netty</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<name>spring-5-reactive-netty</name>
|
||||
<packaging>jar</packaging>
|
||||
<description>Spring 5 sample project about reactive web with Netty server</description>
|
||||
|
||||
<parent>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>parent-boot-2</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<relativePath>../parent-boot-2</relativePath>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-webflux</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-devtools</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
|
@ -0,0 +1,36 @@
|
|||
package com.baeldung.serverconfig;
|
||||
|
||||
import io.netty.channel.EventLoopGroup;
|
||||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
||||
import org.springframework.boot.web.embedded.netty.NettyReactiveWebServerFactory;
|
||||
import org.springframework.boot.web.embedded.netty.NettyServerCustomizer;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
import reactor.netty.http.server.HttpServer;
|
||||
|
||||
@Configuration
|
||||
@Profile("skipAutoConfig")
|
||||
public class CustomNettyWebServerFactory {
|
||||
|
||||
@Bean
|
||||
public NettyReactiveWebServerFactory nettyReactiveWebServerFactory() {
|
||||
NettyReactiveWebServerFactory webServerFactory = new NettyReactiveWebServerFactory();
|
||||
webServerFactory.addServerCustomizers(new EventLoopNettyCustomizer());
|
||||
return webServerFactory;
|
||||
}
|
||||
|
||||
private static class EventLoopNettyCustomizer implements NettyServerCustomizer {
|
||||
|
||||
@Override
|
||||
public HttpServer apply(HttpServer httpServer) {
|
||||
EventLoopGroup parentGroup = new NioEventLoopGroup();
|
||||
EventLoopGroup childGroup = new NioEventLoopGroup();
|
||||
return httpServer
|
||||
.tcpConfiguration(tcpServer -> tcpServer.bootstrap(
|
||||
serverBootstrap -> serverBootstrap.group(parentGroup, childGroup).channel(NioServerSocketChannel.class)
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package com.baeldung.serverconfig;
|
||||
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/greet")
|
||||
public class GreetingController {
|
||||
|
||||
private final GreetingService greetingService;
|
||||
|
||||
public GreetingController(GreetingService greetingService) {
|
||||
this.greetingService = greetingService;
|
||||
}
|
||||
|
||||
@GetMapping("/{name}")
|
||||
private Mono<String> greet(@PathVariable String name) {
|
||||
return greetingService.greet(name);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package com.baeldung.serverconfig;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
@Service
|
||||
public class GreetingService {
|
||||
|
||||
public Mono<String> greet(String name) {
|
||||
return Mono.just("Greeting " + name);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package com.baeldung.serverconfig;
|
||||
|
||||
import org.springframework.boot.web.embedded.netty.NettyReactiveWebServerFactory;
|
||||
import org.springframework.boot.web.embedded.netty.NettyServerCustomizer;
|
||||
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
|
||||
import org.springframework.stereotype.Component;
|
||||
import reactor.netty.http.server.HttpServer;
|
||||
|
||||
@Component
|
||||
public class NettyWebServerFactoryPortCustomizer implements WebServerFactoryCustomizer<NettyReactiveWebServerFactory> {
|
||||
|
||||
@Override
|
||||
public void customize(NettyReactiveWebServerFactory serverFactory) {
|
||||
serverFactory.addServerCustomizers(new PortCustomizer(8443));
|
||||
}
|
||||
|
||||
private static class PortCustomizer implements NettyServerCustomizer {
|
||||
|
||||
private final int port;
|
||||
|
||||
private PortCustomizer(int port) {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpServer apply(HttpServer httpServer) {
|
||||
return httpServer.port(port);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package com.baeldung.serverconfig;
|
||||
|
||||
import org.springframework.boot.web.embedded.netty.NettyReactiveWebServerFactory;
|
||||
import org.springframework.boot.web.embedded.netty.SslServerCustomizer;
|
||||
import org.springframework.boot.web.server.Http2;
|
||||
import org.springframework.boot.web.server.Ssl;
|
||||
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class NettyWebServerFactorySslCustomizer implements WebServerFactoryCustomizer<NettyReactiveWebServerFactory> {
|
||||
|
||||
@Override
|
||||
public void customize(NettyReactiveWebServerFactory serverFactory) {
|
||||
Ssl ssl = new Ssl();
|
||||
ssl.setEnabled(true);
|
||||
ssl.setKeyStore("classpath:sample.jks");
|
||||
ssl.setKeyAlias("alias");
|
||||
ssl.setKeyPassword("password");
|
||||
ssl.setKeyStorePassword("secret");
|
||||
Http2 http2 = new Http2();
|
||||
http2.setEnabled(false);
|
||||
serverFactory.addServerCustomizers(new SslServerCustomizer(ssl, http2, null));
|
||||
serverFactory.setPort(8443);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package com.baeldung.serverconfig;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class ServerConfigApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(ServerConfigApplication.class, args);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
<appender name="Console"
|
||||
class="ch.qos.logback.core.ConsoleAppender">
|
||||
<layout class="ch.qos.logback.classic.PatternLayout">
|
||||
<Pattern>
|
||||
%black(%d{ISO8601}) %highlight(%-5level) [%blue(%t)] %yellow(%C{1.}): %msg%n%throwable
|
||||
</Pattern>
|
||||
</layout>
|
||||
</appender>
|
||||
|
||||
<appender name="AccessLog" class="ch.qos.logback.core.FileAppender">
|
||||
<file>netty-access.log</file>
|
||||
<encoder>
|
||||
<pattern>%msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<appender name="Async" class="ch.qos.logback.classic.AsyncAppender">
|
||||
<appender-ref ref="AccessLog"/>
|
||||
</appender>
|
||||
|
||||
<logger name="reactor.netty.http.server.AccessLog" level="INFO" additivity="false">
|
||||
<appender-ref ref="Console"/>
|
||||
<appender-ref ref="Async"/>
|
||||
</logger>
|
||||
|
||||
<root level="info">
|
||||
<appender-ref ref="Console"/>
|
||||
</root>
|
||||
</configuration>
|
Binary file not shown.
|
@ -0,0 +1,41 @@
|
|||
package com.baeldung.serverconfig;
|
||||
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@WebFluxTest
|
||||
public class GreetingControllerIntegrationTest {
|
||||
|
||||
@Autowired
|
||||
private WebTestClient webClient;
|
||||
|
||||
@MockBean
|
||||
private GreetingService greetingService;
|
||||
|
||||
private final String name = "Baeldung";
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
when(greetingService.greet(name)).thenReturn(Mono.just("Greeting Baeldung"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldGreet() {
|
||||
webClient.get().uri("/greet/{name}", name)
|
||||
.exchange()
|
||||
.expectStatus()
|
||||
.isOk()
|
||||
.expectBody(String.class)
|
||||
.isEqualTo("Greeting Baeldung");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
package com.baeldung.serverconfig;
|
||||
|
||||
import io.netty.handler.ssl.SslContext;
|
||||
import io.netty.handler.ssl.SslContextBuilder;
|
||||
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
|
||||
import javax.net.ssl.SSLException;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient.ResponseSpec;
|
||||
import reactor.netty.http.client.HttpClient;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.DEFINED_PORT)
|
||||
public class GreetingLiveTest {
|
||||
|
||||
private static final String BASE_URL = "https://localhost:8443";
|
||||
|
||||
private WebTestClient webTestClient;
|
||||
|
||||
@Before
|
||||
public void setup() throws SSLException {
|
||||
webTestClient = WebTestClient.bindToServer(getConnector())
|
||||
.baseUrl(BASE_URL)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldGreet() {
|
||||
final String name = "Baeldung";
|
||||
|
||||
ResponseSpec response = webTestClient.get()
|
||||
.uri("/greet/{name}", name)
|
||||
.exchange();
|
||||
|
||||
response.expectStatus()
|
||||
.isOk()
|
||||
.expectBody(String.class)
|
||||
.isEqualTo("Greeting Baeldung");
|
||||
}
|
||||
|
||||
private ReactorClientHttpConnector getConnector() throws SSLException {
|
||||
SslContext sslContext = SslContextBuilder
|
||||
.forClient()
|
||||
.trustManager(InsecureTrustManagerFactory.INSTANCE)
|
||||
.build();
|
||||
HttpClient httpClient = HttpClient.create().secure(t -> t.sslContext(sslContext));
|
||||
return new ReactorClientHttpConnector(httpClient);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package com.baeldung.serverconfig;
|
||||
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
|
||||
@ActiveProfiles("skipAutoConfig")
|
||||
public class GreetingSkipAutoConfigLiveTest extends GreetingLiveTest {
|
||||
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
<appender name="Console" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<layout class="ch.qos.logback.classic.PatternLayout">
|
||||
<Pattern>
|
||||
%black(%d{ISO8601}) %highlight(%-5level) [%blue(%t)] %yellow(%C{1.}): %msg%n%throwable
|
||||
</Pattern>
|
||||
</layout>
|
||||
</appender>
|
||||
<root level="info">
|
||||
<appender-ref ref="Console"/>
|
||||
</root>
|
||||
</configuration>
|
|
@ -0,0 +1,3 @@
|
|||
### Relevant Articles:
|
||||
- [Building a Web Application with Spring Boot and Angular](https://www.baeldung.com/spring-boot-angular-web)
|
||||
|
|
@ -9,7 +9,7 @@ public interface IOperations<T extends Serializable> {
|
|||
|
||||
// read - one
|
||||
|
||||
T findOne(final long id);
|
||||
T findById(final long id);
|
||||
|
||||
// read - all
|
||||
|
||||
|
|
|
@ -18,9 +18,8 @@ public abstract class AbstractService<T extends Serializable> implements IOperat
|
|||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public T findOne(final long id) {
|
||||
return getDao().findById(id)
|
||||
.get();
|
||||
public T findById(final long id) {
|
||||
return getDao().findById(id).orElse(null);
|
||||
}
|
||||
|
||||
// read - all
|
||||
|
|
|
@ -55,7 +55,7 @@ public class WebConfig implements WebMvcConfigurer {
|
|||
@Bean
|
||||
public FilterRegistrationBean<ShallowEtagHeaderFilter> shallowEtagHeaderFilter() {
|
||||
FilterRegistrationBean<ShallowEtagHeaderFilter> filterRegistrationBean = new FilterRegistrationBean<>( new ShallowEtagHeaderFilter());
|
||||
filterRegistrationBean.addUrlPatterns("/auth/foos/*");
|
||||
filterRegistrationBean.addUrlPatterns("/foos/*");
|
||||
filterRegistrationBean.setName("etagFilter");
|
||||
return filterRegistrationBean;
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
|||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
|
||||
import com.baeldung.persistence.model.Foo;
|
||||
|
@ -32,7 +33,7 @@ import com.baeldung.web.util.RestPreconditions;
|
|||
import com.google.common.base.Preconditions;
|
||||
|
||||
@RestController
|
||||
@RequestMapping(value = "/auth/foos")
|
||||
@RequestMapping(value = "/foos")
|
||||
public class FooController {
|
||||
|
||||
@Autowired
|
||||
|
@ -51,22 +52,29 @@ public class FooController {
|
|||
@GetMapping(value = "/{id}/custom-etag")
|
||||
public ResponseEntity<Foo> findByIdWithCustomEtag(@PathVariable("id") final Long id,
|
||||
final HttpServletResponse response) {
|
||||
final Foo resourceById = RestPreconditions.checkFound(service.findOne(id));
|
||||
final Foo foo = RestPreconditions.checkFound(service.findById(id));
|
||||
|
||||
eventPublisher.publishEvent(new SingleResourceRetrievedEvent(this, response));
|
||||
return ResponseEntity.ok()
|
||||
.eTag(Long.toString(resourceById.getVersion()))
|
||||
.body(resourceById);
|
||||
.eTag(Long.toString(foo.getVersion()))
|
||||
.body(foo);
|
||||
}
|
||||
|
||||
// read - one
|
||||
|
||||
@GetMapping(value = "/{id}")
|
||||
public Foo findById(@PathVariable("id") final Long id, final HttpServletResponse response) {
|
||||
final Foo resourceById = RestPreconditions.checkFound(service.findOne(id));
|
||||
try {
|
||||
final Foo resourceById = RestPreconditions.checkFound(service.findById(id));
|
||||
|
||||
eventPublisher.publishEvent(new SingleResourceRetrievedEvent(this, response));
|
||||
return resourceById;
|
||||
}
|
||||
catch (MyResourceNotFoundException exc) {
|
||||
throw new ResponseStatusException(
|
||||
HttpStatus.NOT_FOUND, "Foo Not Found", exc);
|
||||
}
|
||||
|
||||
eventPublisher.publishEvent(new SingleResourceRetrievedEvent(this, response));
|
||||
return resourceById;
|
||||
}
|
||||
|
||||
// read - all
|
||||
|
@ -120,7 +128,7 @@ public class FooController {
|
|||
@ResponseStatus(HttpStatus.OK)
|
||||
public void update(@PathVariable("id") final Long id, @RequestBody final Foo resource) {
|
||||
Preconditions.checkNotNull(resource);
|
||||
RestPreconditions.checkFound(service.findOne(resource.getId()));
|
||||
RestPreconditions.checkFound(service.findById(resource.getId()));
|
||||
service.update(resource);
|
||||
}
|
||||
|
||||
|
|
|
@ -7,34 +7,28 @@ import javax.servlet.http.HttpServletResponse;
|
|||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
import org.springframework.web.util.UriTemplate;
|
||||
|
||||
import com.baeldung.web.util.LinkUtil;
|
||||
|
||||
@Controller
|
||||
@RequestMapping(value = "/auth/")
|
||||
public class RootController {
|
||||
|
||||
public RootController() {
|
||||
super();
|
||||
}
|
||||
|
||||
// API
|
||||
|
||||
// discover
|
||||
|
||||
@RequestMapping(value = "admin", method = RequestMethod.GET)
|
||||
@GetMapping("/")
|
||||
@ResponseStatus(value = HttpStatus.NO_CONTENT)
|
||||
public void adminRoot(final HttpServletRequest request, final HttpServletResponse response) {
|
||||
final String rootUri = request.getRequestURL()
|
||||
.toString();
|
||||
|
||||
final URI fooUri = new UriTemplate("{rootUri}/{resource}").expand(rootUri, "foo");
|
||||
final String linkToFoo = LinkUtil.createLinkHeader(fooUri.toASCIIString(), "collection");
|
||||
response.addHeader("Link", linkToFoo);
|
||||
final URI fooUri = new UriTemplate("{rootUri}{resource}").expand(rootUri, "foos");
|
||||
final String linkToFoos = LinkUtil.createLinkHeader(fooUri.toASCIIString(), "collection");
|
||||
response.addHeader("Link", linkToFoos);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
package com.baeldung.web.controller.students;
|
||||
|
||||
public class Student {
|
||||
|
||||
private long id;
|
||||
private String firstName;
|
||||
private String lastName;
|
||||
|
||||
public Student() {}
|
||||
|
||||
public Student(String firstName, String lastName) {
|
||||
super();
|
||||
this.firstName = firstName;
|
||||
this.lastName = lastName;
|
||||
}
|
||||
|
||||
public Student(long id, String firstName, String lastName) {
|
||||
super();
|
||||
this.id = id;
|
||||
this.firstName = firstName;
|
||||
this.lastName = lastName;
|
||||
}
|
||||
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getFirstName() {
|
||||
return firstName;
|
||||
}
|
||||
|
||||
public void setFirstName(String firstName) {
|
||||
this.firstName = firstName;
|
||||
}
|
||||
|
||||
public String getLastName() {
|
||||
return lastName;
|
||||
}
|
||||
|
||||
public void setLastName(String lastName) {
|
||||
this.lastName = lastName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Student [id=" + id + ", firstName=" + firstName + ", lastName=" + lastName + "]";
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
package com.baeldung.web.controller.students;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
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 org.springframework.web.servlet.support.ServletUriComponentsBuilder;
|
||||
import com.baeldung.web.controller.students.StudentService;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/students")
|
||||
public class StudentController {
|
||||
|
||||
@Autowired
|
||||
private StudentService service;
|
||||
|
||||
@GetMapping("/")
|
||||
public List<Student> read() {
|
||||
return service.readAll();
|
||||
}
|
||||
|
||||
@GetMapping("/{id}")
|
||||
public ResponseEntity<Student> read(@PathVariable("id") Long id) {
|
||||
Student foundStudent = service.read(id);
|
||||
if (foundStudent == null) {
|
||||
return ResponseEntity.notFound().build();
|
||||
} else {
|
||||
return ResponseEntity.ok(foundStudent);
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/")
|
||||
public ResponseEntity<Student> create(@RequestBody Student student) throws URISyntaxException {
|
||||
Student createdStudent = service.create(student);
|
||||
|
||||
URI uri = ServletUriComponentsBuilder.fromCurrentRequest()
|
||||
.path("/{id}")
|
||||
.buildAndExpand(createdStudent.getId())
|
||||
.toUri();
|
||||
|
||||
return ResponseEntity.created(uri)
|
||||
.body(createdStudent);
|
||||
|
||||
}
|
||||
|
||||
@PutMapping("/{id}")
|
||||
public ResponseEntity<Student> update(@RequestBody Student student, @PathVariable Long id) {
|
||||
Student updatedStudent = service.update(id, student);
|
||||
if (updatedStudent == null) {
|
||||
return ResponseEntity.notFound().build();
|
||||
} else {
|
||||
return ResponseEntity.ok(updatedStudent);
|
||||
}
|
||||
}
|
||||
|
||||
@DeleteMapping("/{id}")
|
||||
public ResponseEntity<Object> deleteStudent(@PathVariable Long id) {
|
||||
service.delete(id);
|
||||
|
||||
return ResponseEntity.noContent().build();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
package com.baeldung.web.controller.students;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class StudentService {
|
||||
|
||||
// DB repository mock
|
||||
private Map<Long, Student> repository = Arrays.asList(
|
||||
new Student[]{
|
||||
new Student(1, "Alan","Turing"),
|
||||
new Student(2, "Sebastian","Bach"),
|
||||
new Student(3, "Pablo","Picasso"),
|
||||
}).stream()
|
||||
.collect(Collectors.toConcurrentMap(s -> s.getId(), Function.identity()));
|
||||
|
||||
// DB id sequence mock
|
||||
private AtomicLong sequence = new AtomicLong(3);
|
||||
|
||||
public List<Student> readAll() {
|
||||
return repository.values().stream().collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public Student read(Long id) {
|
||||
return repository.get(id);
|
||||
}
|
||||
|
||||
public Student create(Student student) {
|
||||
long key = sequence.incrementAndGet();
|
||||
student.setId(key);
|
||||
repository.put(key, student);
|
||||
return student;
|
||||
}
|
||||
|
||||
public Student update(Long id, Student student) {
|
||||
student.setId(id);
|
||||
Student oldStudent = repository.replace(id, student);
|
||||
return oldStudent == null ? null : student;
|
||||
}
|
||||
|
||||
public void delete(Long id) {
|
||||
repository.remove(id);
|
||||
}
|
||||
}
|
|
@ -115,7 +115,7 @@ class PaginatedResultsRetrievedDiscoverabilityListener implements ApplicationLis
|
|||
protected void plural(final UriComponentsBuilder uriBuilder, final Class clazz) {
|
||||
final String resourceName = clazz.getSimpleName()
|
||||
.toLowerCase() + "s";
|
||||
uriBuilder.path("/auth/" + resourceName);
|
||||
uriBuilder.path("/" + resourceName);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
server.port=8082
|
||||
server.servlet.context-path=/spring-boot-rest
|
||||
|
||||
### Spring Boot default error handling configurations
|
||||
#server.error.whitelabel.enabled=false
|
||||
#server.error.include-stacktrace=always
|
||||
#server.error.include-stacktrace=always
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
package com.baeldung;
|
||||
|
||||
public interface Consts {
|
||||
int APPLICATION_PORT = 8082;
|
||||
int APPLICATION_PORT = 8080;
|
||||
}
|
||||
|
|
|
@ -59,7 +59,7 @@ public abstract class AbstractLiveTest<T extends Serializable> {
|
|||
//
|
||||
|
||||
protected String getURL() {
|
||||
return "http://localhost:" + APPLICATION_PORT + "/spring-boot-rest/auth/foos";
|
||||
return "http://localhost:" + APPLICATION_PORT + "/spring-boot-rest/foos";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ public class FooControllerAppIntegrationTest {
|
|||
|
||||
@Test
|
||||
public void whenFindPaginatedRequest_thenEmptyResponse() throws Exception {
|
||||
this.mockMvc.perform(get("/auth/foos").param("page", "0")
|
||||
this.mockMvc.perform(get("/foos").param("page", "0")
|
||||
.param("size", "2"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().json("[]"));
|
||||
|
|
|
@ -29,7 +29,7 @@ public class FooControllerCustomEtagIntegrationTest {
|
|||
@Autowired
|
||||
private MockMvc mvc;
|
||||
|
||||
private String FOOS_ENDPOINT = "/auth/foos/";
|
||||
private String FOOS_ENDPOINT = "/foos/";
|
||||
private String CUSTOM_ETAG_ENDPOINT_SUFFIX = "/custom-etag";
|
||||
|
||||
private static String serializeFoo(Foo foo) throws Exception {
|
||||
|
|
|
@ -51,7 +51,7 @@ public class FooControllerWebLayerIntegrationTest {
|
|||
doNothing().when(publisher)
|
||||
.publishEvent(any(PaginatedResultsRetrievedEvent.class));
|
||||
|
||||
this.mockMvc.perform(get("/auth/foos").param("page", "0")
|
||||
this.mockMvc.perform(get("/foos").param("page", "0")
|
||||
.param("size", "2"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$",Matchers.hasSize(1)));
|
||||
|
|
|
@ -74,7 +74,7 @@ public class FooPageableLiveTest extends AbstractBasicLiveTest<Foo> {
|
|||
}
|
||||
|
||||
protected String getPageableURL() {
|
||||
return "http://localhost:" + APPLICATION_PORT + "/spring-boot-rest/auth/foos/pageable";
|
||||
return "http://localhost:" + APPLICATION_PORT + "/spring-boot-rest/foos/pageable";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
package com.baeldung.web;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.web.server.MediaTypeNotSupportedStatusException;
|
||||
|
||||
import com.baeldung.web.controller.students.Student;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest
|
||||
@AutoConfigureMockMvc
|
||||
public class StudentControllerIntegrationTest {
|
||||
|
||||
private static final String STUDENTS_PATH = "/students/";
|
||||
|
||||
@Autowired
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@Test
|
||||
public void whenReadAll_thenStatusIsOk() throws Exception {
|
||||
this.mockMvc.perform(get(STUDENTS_PATH))
|
||||
.andExpect(status().isOk());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenReadOne_thenStatusIsOk() throws Exception {
|
||||
this.mockMvc.perform(get(STUDENTS_PATH + 1))
|
||||
.andExpect(status().isOk());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenCreate_thenStatusIsCreated() throws Exception {
|
||||
Student student = new Student(10, "Albert", "Einstein");
|
||||
this.mockMvc.perform(post(STUDENTS_PATH).content(asJsonString(student))
|
||||
.contentType(MediaType.APPLICATION_JSON_VALUE))
|
||||
.andExpect(status().isCreated());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenUpdate_thenStatusIsOk() throws Exception {
|
||||
Student student = new Student(1, "Nikola", "Tesla");
|
||||
this.mockMvc.perform(put(STUDENTS_PATH + 1)
|
||||
.content(asJsonString(student))
|
||||
.contentType(MediaType.APPLICATION_JSON_VALUE))
|
||||
.andExpect(status().isOk());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenDelete_thenStatusIsNoContent() throws Exception {
|
||||
this.mockMvc.perform(delete(STUDENTS_PATH + 3))
|
||||
.andExpect(status().isNoContent());
|
||||
}
|
||||
|
||||
private String asJsonString(final Object obj) {
|
||||
try {
|
||||
return new ObjectMapper().writeValueAsString(obj);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -42,15 +42,14 @@
|
|||
"raw": "{\n \"name\": \"Transformers\"\n}"
|
||||
},
|
||||
"url": {
|
||||
"raw": "http://localhost:8082/spring-boot-rest/auth/foos",
|
||||
"raw": "http://localhost:8080/spring-boot-rest/foos",
|
||||
"protocol": "http",
|
||||
"host": [
|
||||
"localhost"
|
||||
],
|
||||
"port": "8082",
|
||||
"port": "8080",
|
||||
"path": [
|
||||
"spring-boot-rest",
|
||||
"auth",
|
||||
"foos"
|
||||
]
|
||||
}
|
||||
|
@ -85,15 +84,14 @@
|
|||
"raw": ""
|
||||
},
|
||||
"url": {
|
||||
"raw": "http://localhost:8082/spring-boot-rest/auth/foos/{{id}}",
|
||||
"raw": "http://localhost:8080/spring-boot-rest/foos/{{id}}",
|
||||
"protocol": "http",
|
||||
"host": [
|
||||
"localhost"
|
||||
],
|
||||
"port": "8082",
|
||||
"port": "8080",
|
||||
"path": [
|
||||
"spring-boot-rest",
|
||||
"auth",
|
||||
"foos",
|
||||
"{{id}}"
|
||||
]
|
||||
|
@ -123,15 +121,14 @@
|
|||
"raw": ""
|
||||
},
|
||||
"url": {
|
||||
"raw": "http://localhost:8082/spring-boot-rest/auth/foos/{{id}}",
|
||||
"raw": "http://localhost:8080/spring-boot-rest/foos/{{id}}",
|
||||
"protocol": "http",
|
||||
"host": [
|
||||
"localhost"
|
||||
],
|
||||
"port": "8082",
|
||||
"port": "8080",
|
||||
"path": [
|
||||
"spring-boot-rest",
|
||||
"auth",
|
||||
"foos",
|
||||
"{{id}}"
|
||||
]
|
||||
|
@ -164,15 +161,14 @@
|
|||
"raw": ""
|
||||
},
|
||||
"url": {
|
||||
"raw": "http://localhost:8082/spring-boot-rest/auth/foos/{{id}}",
|
||||
"raw": "http://localhost:8080/spring-boot-rest/foos/{{id}}",
|
||||
"protocol": "http",
|
||||
"host": [
|
||||
"localhost"
|
||||
],
|
||||
"port": "8082",
|
||||
"port": "8080",
|
||||
"path": [
|
||||
"spring-boot-rest",
|
||||
"auth",
|
||||
"foos",
|
||||
"{{id}}"
|
||||
]
|
||||
|
|
|
@ -61,6 +61,12 @@
|
|||
<artifactId>spring-security-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-autoconfigure</artifactId>
|
||||
<version>2.1.1.RELEASE</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
package com.baeldung.springbootsecurity.oauth2server.config;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
|
||||
@Configuration
|
||||
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Bean
|
||||
public AuthenticationManager customAuthenticationManager() throws Exception {
|
||||
return authenticationManager();
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
package com.baeldung.springbootsecurity.oauth2sso;
|
||||
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
import org.springframework.boot.autoconfigure.security.oauth2.client.EnableOAuth2Sso;
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
security.user.password=password
|
||||
spring.security.user.password=password
|
||||
security.oauth2.client.client-id=client
|
||||
security.oauth2.client.client-secret=secret
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
#jsp config
|
||||
spring.mvc.view.prefix: /WEB-INF/views/
|
||||
spring.mvc.view.suffix: .jsp
|
||||
spring.mvc.view.prefix= /WEB-INF/views/
|
||||
spring.mvc.view.suffix= .jsp
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
package com.baeldung.springbootsecurity.basic_auth;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.boot.web.server.LocalServerPort;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||
import org.springframework.boot.web.server.LocalServerPort;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
|
|
@ -13,7 +13,7 @@ import org.springframework.test.context.junit4.SpringRunner;
|
|||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, classes = SpringBootSecurityTagLibsApplication.class)
|
||||
public class HomeControllerIntegrationTest {
|
||||
public class HomeControllerUnitTest {
|
||||
|
||||
@Autowired
|
||||
private TestRestTemplate restTemplate;
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue