Merge branch 'eugenp:master' into master

This commit is contained in:
Ulisses Lima 2022-02-22 15:10:27 -03:00 committed by GitHub
commit 36ecf023d4
94 changed files with 2624 additions and 206 deletions

View File

@ -32,9 +32,27 @@
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>${maven.resources.plugin.version}</version>
<configuration>
<encoding>UTF-8</encoding>
<nonFilteredFileExtensions>
<nonFilteredFileExtension>xlsx</nonFilteredFileExtension>
<nonFilteredFileExtension>xls</nonFilteredFileExtension>
</nonFilteredFileExtensions>
</configuration>
</plugin>
</plugins>
</build>
<properties>
<poi.version>5.2.0</poi.version>
<jexcel.version>1.0.6</jexcel.version>
<maven.resources.plugin.version>3.2.0</maven.resources.plugin.version>
</properties>
</project>

View File

@ -12,7 +12,7 @@ import java.nio.file.Paths;
import static org.junit.Assert.assertEquals;
public class CellBorderHandlerUnitTest {
private static final String FILE_NAME = "cellstyle/CellStyleHandlerTest.xlsx";
private static final String FILE_NAME = "cellstyle/CellStyleBorderHandlerTest.xlsx";
private static final int SHEET_INDEX = 0;
private static CellBordersHandler cellBordersHandler;

View File

@ -0,0 +1,66 @@
package com.baeldung.game;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.Scanner;
class RockPaperScissorsGame {
private static Map<Integer, String> movesMap = new HashMap<Integer, String>() {{
put(0, "rock");
put(1, "paper");
put(2, "scissors");
}};
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int wins = 0;
int losses = 0;
System.out.println("Welcome to Rock-Paper-Scissors! Please enter \"rock\", \"paper\", \"scissors\", or \"quit\" to exit.");
while (true) {
System.out.println("-------------------------");
System.out.print("Enter your move: ");
String playerMove = scanner.nextLine();
if (playerMove.equals("quit")) {
System.out.println("You won " + wins + " times and lost " + losses + " times.");
System.out.println("Thanks for playing! See you again.");
break;
}
if (!movesMap.containsValue(playerMove)) {
System.out.println("Your move isn't valid!");
continue;
}
String computerMove = getComputerMove();
if (playerMove.equals(computerMove)) {
System.out.println("It's a tie!");
} else if (isPlayerWin(playerMove, computerMove)) {
System.out.println("You won!");
wins++;
} else {
System.out.println("You lost!");
losses++;
}
}
}
private static boolean isPlayerWin(String playerMove, String computerMove) {
return playerMove.equals("rock") && computerMove.equals("scissors")
|| (playerMove.equals("scissors") && computerMove.equals("paper"))
|| (playerMove.equals("paper") && computerMove.equals("rock"));
}
private static String getComputerMove() {
Random random = new Random();
int randomNumber = random.nextInt(3);
String computerMove = movesMap.get(randomNumber);
System.out.println("Computer move: " + computerMove);
return computerMove;
}
}

View File

@ -0,0 +1,33 @@
package com.baeldung.uuid;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.UUID;
public class UuidHelper {
public static byte[] convertUUIDToBytes(UUID uuid) {
ByteBuffer bb = ByteBuffer.wrap(new byte[16]);
bb.putLong(uuid.getMostSignificantBits());
bb.putLong(uuid.getLeastSignificantBits());
return bb.array();
}
public static UUID convertBytesToUUID(byte[] bytes) {
ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
long high = byteBuffer.getLong();
long low = byteBuffer.getLong();
return new UUID(high, low);
}
public static void main(String[] args) {
UUID uuid = UUID.randomUUID();
System.out.println("Original UUID: " + uuid);
byte[] bytes = convertUUIDToBytes(uuid);
System.out.println("Converted byte array: " + Arrays.toString(bytes));
UUID uuidNew = convertBytesToUUID(bytes);
System.out.println("Converted UUID: " + uuidNew);
}
}

View File

@ -0,0 +1,56 @@
package com.baeldung.maps.initialize;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.NavigableMap;
import java.util.SortedMap;
import java.util.TreeMap;
public class EmptyMapInitializer {
public static Map<String, String> articleMap;
static {
articleMap = new HashMap<>();
}
public static Map<String, String> createEmptyMap() {
return Collections.emptyMap();
}
public void createMapUsingConstructors() {
Map hashMap = new HashMap();
Map linkedHashMap = new LinkedHashMap();
Map treeMap = new TreeMap();
}
public Map<String, String> createEmptyMapUsingMapsObject() {
Map<String, String> emptyMap = Maps.newHashMap();
return emptyMap;
}
public Map createGenericEmptyMapUsingMapsObject() {
Map genericEmptyMap = Maps.<String, Integer>newHashMap();
return genericEmptyMap;
}
public static Map<String, String> createMapUsingGuava() {
Map<String, String> emptyMapUsingGuava =
Maps.newHashMap(ImmutableMap.of());
return emptyMapUsingGuava;
}
public SortedMap<String, String> createEmptySortedMap() {
SortedMap<String, String> sortedMap = Collections.emptySortedMap();
return sortedMap;
}
public NavigableMap<String, String> createEmptyNavigableMap() {
NavigableMap<String, String> navigableMap = Collections.emptyNavigableMap();
return navigableMap;
}
}

View File

@ -0,0 +1,31 @@
package com.baeldung.maps.initialize;
import java.util.Map;
import org.junit.Test;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class EmptyMapInitializerUnitTest {
@Test(expected=UnsupportedOperationException.class)
public void givenEmptyMap_whenAddingEntries_throwsException() {
Map<String, String> map = EmptyMapInitializer.createEmptyMap();
map.put("key", "value");
}
@Test
public void givenEmptyMap_whenChecked_returnsTrue() {
assertTrue(EmptyMapInitializer.articleMap.isEmpty());
}
@Test
public void givenEmptyMap_whenCreatedUsingGuava_returnsEmptyOrNot() {
Map<String, String> emptyMapUsingGuava =
EmptyMapInitializer.createMapUsingGuava();
assertTrue(emptyMapUsingGuava.isEmpty());
emptyMapUsingGuava.put("key", "value");
assertFalse(emptyMapUsingGuava.isEmpty());
}
}

View File

@ -0,0 +1,25 @@
package com.baeldung.mapandhashmap;
import com.baeldung.mapandhashmap.printer.HashMapPrinter;
import com.baeldung.mapandhashmap.printer.MapPrinter;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
public class Main {
public static void main(String[] args) {
Map<String, String> map = new HashMap<>();
HashMap<String, String> hashMap = new HashMap<>();
TreeMap<String, String> treeMap = new TreeMap<>();
HashMapPrinter hashMapPrinter = new HashMapPrinter();
hashMapPrinter.printMap(hashMap);
// hashMapPrinter.printMap(treeMap); Compile time error
// hashMapPrinter.printMap(map); Compile time error
MapPrinter mapPrinter = new MapPrinter();
mapPrinter.printMap(hashMap);
mapPrinter.printMap(treeMap);
mapPrinter.printMap(map);
}
}

View File

@ -0,0 +1,13 @@
package com.baeldung.mapandhashmap.printer;
import java.util.HashMap;
import java.util.Map.Entry;
public class HashMapPrinter {
public void printMap(final HashMap<?, ?> map) {
for (final Entry<?, ?> entry : map.entrySet()) {
System.out.println(entry.getKey() + " " + entry.getValue());
}
}
}

View File

@ -0,0 +1,13 @@
package com.baeldung.mapandhashmap.printer;
import java.util.Map;
import java.util.Map.Entry;
public class MapPrinter {
public void printMap(final Map<?, ?> map) {
for (final Entry<?, ?> entry : map.entrySet()) {
System.out.println(entry.getKey() + " " + entry.getValue());
}
}
}

View File

@ -0,0 +1,19 @@
package com.baeldung.mapandhashmap.printer;
import java.util.Map;
import java.util.Map.Entry;
public class MapReporter {
private final Map<?, ?> map;
public MapReporter(final Map<?, ?> map) {
this.map = map;
}
public void printMap() {
for (final Entry<?, ?> entry : this.map.entrySet()) {
System.out.println(entry.getKey() + " " + entry.getValue());
}
}
}

View File

@ -0,0 +1,56 @@
package com.baeldung.mapandhashmap.printer;
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.util.HashMap;
import java.util.LinkedHashMap;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
class HashMapPrinterUnitTest {
private final HashMapPrinter mapPrinter = new HashMapPrinter();
private final ByteArrayOutputStream outputStreamCaptor = new ByteArrayOutputStream();
@BeforeEach
public void setUp() {
System.setOut(new PrintStream(outputStreamCaptor));
}
@Test
@DisplayName("Test hash map printer with HashMap")
void testPrintHashMap() {
// given
String key = "HashMap";
String value = "Main default implementation for the Map interface";
String expected = key + " " + value;
HashMap<String, String> map = new HashMap<>();
map.put(key, value);
// when
mapPrinter.printMap(map);
// then
String actual = outputStreamCaptor.toString().trim();
assertThat(actual).isEqualTo(expected);
}
@Test
@DisplayName("Test hash map printer with LinkedHash")
void testPrintLinkedHashMap() {
// given
String key = "LinkedHashMap";
String value = "Use this implementation if you need keep the order of elements";
String expected = key + " " + value;
LinkedHashMap<String, String> map = new LinkedHashMap<>();
map.put(key, value);
// when
mapPrinter.printMap(map);
// then
String actual = outputStreamCaptor.toString().trim();
assertThat(actual).isEqualTo(expected);
}
}

View File

@ -0,0 +1,71 @@
package com.baeldung.mapandhashmap.printer;
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.TreeMap;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
class MapPrinterUnitTest {
private final MapPrinter mapPrinter = new MapPrinter();
private final ByteArrayOutputStream outputStreamCaptor = new ByteArrayOutputStream();
@BeforeEach
public void setUp() {
System.setOut(new PrintStream(outputStreamCaptor));
}
@Test
@DisplayName("Test printer with TreeMap")
void testPrintTreeMap() {
// given
String key = "TreeMap";
String value = "Used when sorting is needed";
String expected = key + " " + value;
TreeMap<String, String> map = new TreeMap<>();
map.put(key, value);
// when
mapPrinter.printMap(map);
// then
String actual = outputStreamCaptor.toString().trim();
assertThat(actual).isEqualTo(expected);
}
@Test
@DisplayName("Test printer with HashMap")
void testPrintHashMap() {
// given
String key = "HashMap";
String value = "Main default implementation for the Map interface";
String expected = key + " " + value;
HashMap<String, String> map = new HashMap<>();
map.put(key, value);
// when
mapPrinter.printMap(map);
// then
String actual = outputStreamCaptor.toString().trim();
assertThat(actual).isEqualTo(expected);
}
@Test
@DisplayName("Test printer with LinkedHash")
void testPrintLinkedHashMap() {
// given
String key = "LinkedHashMap";
String value = "Use this implementation if you need keep the order of elements";
String expected = key + " " + value;
LinkedHashMap<String, String> map = new LinkedHashMap<>();
map.put(key, value);
// when
mapPrinter.printMap(map);
// then
String actual = outputStreamCaptor.toString().trim();
assertThat(actual).isEqualTo(expected);
}
}

View File

@ -0,0 +1,74 @@
package com.baeldung.mapandhashmap.printer;
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.TreeMap;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
class MapReporterUnitTest {
private final ByteArrayOutputStream outputStreamCaptor = new ByteArrayOutputStream();
@BeforeEach
public void setUp() {
System.setOut(new PrintStream(outputStreamCaptor));
}
@Test
@DisplayName("Test reporter with TreeMap")
void testPrintTreeMap() {
// given
String key = "TreeMap";
String value = "Used when sorting is needed";
String expected = key + " " + value;
TreeMap<String, String> map = new TreeMap<>();
map.put(key, value);
// when
MapReporter mapReporter = new MapReporter(map);
mapReporter.printMap();
// then
String actual = outputStreamCaptor.toString().trim();
assertThat(actual).isEqualTo(expected);
}
@Test
@DisplayName("Test reporter with HashMap")
void testPrintHashMap() {
// given
String key = "HashMap";
String value = "Main default implementation for the Map interface";
String expected = key + " " + value;
HashMap<String, String> map = new HashMap<>();
map.put(key, value);
// when
MapReporter mapReporter = new MapReporter(map);
mapReporter.printMap();
// then
String actual = outputStreamCaptor.toString().trim();
assertThat(actual).isEqualTo(expected);
}
@Test
@DisplayName("Test reporter with LinkedHash")
void testPrintLinkedHashMap() {
// given
String key = "LinkedHashMap";
String value = "Use this implementation if you need keep the order of elements";
String expected = key + " " + value;
LinkedHashMap<String, String> map = new LinkedHashMap<>();
map.put(key, value);
// when
MapReporter mapReporter = new MapReporter(map);
mapReporter.printMap();
// then
String actual = outputStreamCaptor.toString().trim();
assertThat(actual).isEqualTo(expected);
}
}

View File

@ -1,25 +1,22 @@
package com.baeldung.atomicstampedreference;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicStampedReference;
public class StampedAccount {
private AtomicInteger stamp = new AtomicInteger(0);
private AtomicStampedReference<Integer> account = new AtomicStampedReference<>(0, 0);
public int getBalance() {
return account.getReference();
}
public int getStamp() {
return account.getStamp();
}
private final AtomicInteger stamp = new AtomicInteger(0);
private final AtomicStampedReference<Integer> account = new AtomicStampedReference<>(0, 0);
public boolean deposit(int funds) {
int[] stamps = new int[1];
int current = this.account.get(stamps);
int newStamp = this.stamp.incrementAndGet();
// Thread is paused here to allow other threads to update the stamp and amount (for testing only)
sleep();
return this.account.compareAndSet(current, current + funds, stamps[0], newStamp);
}
@ -29,4 +26,19 @@ public class StampedAccount {
int newStamp = this.stamp.incrementAndGet();
return this.account.compareAndSet(current, current - funds, stamps[0], newStamp);
}
public int getBalance() {
return account.getReference();
}
public int getStamp() {
return account.getStamp();
}
private static void sleep() {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException ignored) {
}
}
}

View File

@ -1,21 +1,38 @@
package com.baeldung.atomicstampedreference;
import org.junit.Assert;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
public class ThreadStampedAccountUnitTest {
@Test
public void givenMultiThread_whenStampedAccount_thenSetBalance() throws InterruptedException {
StampedAccount account = new StampedAccount();
Thread t = new Thread(() -> {
while (!account.withdrawal(100))
while (!account.deposit(100)) {
Thread.yield();
}
});
t.start();
Assert.assertTrue(account.deposit(100));
t.join(1_000);
Assert.assertFalse(t.isAlive());
Assert.assertSame(0, account.getBalance());
Thread t2 = new Thread(() -> {
while (!account.withdrawal(100)) {
Thread.yield();
}
});
t2.start();
t.join(10_000);
t2.join(10_000);
assertFalse(t.isAlive());
assertFalse(t2.isAlive());
assertEquals(0, account.getBalance());
assertTrue(account.getStamp() > 0);
}
}

View File

@ -16,12 +16,17 @@ class LongRunningAction implements Runnable {
public void run() {
System.out.println("This is phase " + ph.getPhase());
System.out.println("Thread " + threadName + " before long running action");
ph.arriveAndAwaitAdvance();
try {
Thread.sleep(20);
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Thread " + threadName + " action completed and waiting for others");
ph.arriveAndAwaitAdvance();
System.out.println("Thread " + threadName + " proceeding in phase " + ph.getPhase());
ph.arriveAndDeregister();
}
}

View File

@ -26,13 +26,20 @@ public class PhaserUnitTest {
executorService.submit(new LongRunningAction("thread-3", ph));
//then
System.out.println("Thread " + Thread.currentThread().getName() + " waiting for others");
ph.arriveAndAwaitAdvance();
System.out.println("Thread " + Thread.currentThread().getName() + " proceeding in phase " + ph.getPhase());
assertEquals(1, ph.getPhase());
//and
executorService.submit(new LongRunningAction("thread-4", ph));
executorService.submit(new LongRunningAction("thread-5", ph));
System.out.println("Thread " + Thread.currentThread().getName() + " waiting for others");
ph.arriveAndAwaitAdvance();
System.out.println("Thread " + Thread.currentThread().getName() + " proceeding in phase " + ph.getPhase());
assertEquals(2, ph.getPhase());

View File

@ -0,0 +1,41 @@
package com.baeldung.exception.missingreturnstatement;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class MissingReturnStatement {
public static void main(String[] args) {
int a = -12;
int result = pow(a);
System.out.println(result);
Map<String, Integer> dictionary = createDictionary();
dictionary.forEach((s, integer) -> System.out.println(s + " " + integer));
}
public static int pow(int number) {
int pow = number * number;
return pow;
}
public static String checkNumber(int number) {
if (number == 0) {
return "It's equals to zero";
}
for (int i = 0; i < number; i++) {
if (i > 100) {
return "It's a big number";
}
}
return "It's a negative number";
}
public static Map<String, Integer> createDictionary() {
List<String> words = Arrays.asList("Hello", "World");
return words.stream()
.collect(Collectors.toMap(s -> s, s -> 1));
}
}

View File

@ -0,0 +1,38 @@
package com.baeldung.exception.missingreturnstatement;
import static org.junit.Assert.assertEquals;
import java.util.Map;
import org.junit.Test;
public class MissingReturnStatementUnitTest {
@Test
public void givenANumber_thenReturnItsPow() {
int number = 10;
int pow = MissingReturnStatement.pow(number);
assertEquals(100, pow);
}
@Test
public void givenABigNumber_thenReturnItsType() {
int number = 200;
String type = MissingReturnStatement.checkNumber(number);
assertEquals("It's a big number", type);
}
@Test
public void givenANegativeNumber_thenReturnItsType() {
int number = -10;
String type = MissingReturnStatement.checkNumber(number);
assertEquals("It's a negative number", type);
}
@Test
public void getStringDictionary_thenPrintValues() {
Map<String, Integer> dictionary = MissingReturnStatement.createDictionary();
assertEquals(2, dictionary.size());
dictionary.forEach((s, integer) -> System.out.println(s + " - " + integer));
}
}

View File

@ -259,110 +259,7 @@
</plugins>
</build>
</profile>
<!-- java instrumentation profiles to build jars -->
<profile>
<id>buildAgentLoader</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>jar</goal>
</goals>
<configuration>
<classifier>agentLoader</classifier>
<classesDirectory>target/classes</classesDirectory>
<archive>
<manifest>
<addClasspath>true</addClasspath>
</manifest>
<manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
</archive>
<includes>
<include>com/baeldung/instrumentation/application/AgentLoader.class</include>
<include>com/baeldung/instrumentation/application/Launcher.class</include>
</includes>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>buildApplication</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>jar</goal>
</goals>
<configuration>
<classifier>application</classifier>
<classesDirectory>target/classes</classesDirectory>
<archive>
<manifest>
<addClasspath>true</addClasspath>
</manifest>
<manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
</archive>
<includes>
<include>com/baeldung/instrumentation/application/MyAtm.class</include>
<include>com/baeldung/instrumentation/application/MyAtmApplication.class</include>
<include>com/baeldung/instrumentation/application/Launcher.class</include>
</includes>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>buildAgent</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>jar</goal>
</goals>
<configuration>
<classifier>agent</classifier>
<classesDirectory>target/classes</classesDirectory>
<archive>
<manifest>
<addClasspath>true</addClasspath>
</manifest>
<manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
</archive>
<includes>
<include>com/baeldung/instrumentation/agent/AtmTransformer.class</include>
<include>com/baeldung/instrumentation/agent/MyInstrumentationAgent.class</include>
</includes>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<properties>

View File

@ -15,3 +15,13 @@ This module contains articles about working with the Java Virtual Machine (JVM).
- [What Causes java.lang.OutOfMemoryError: unable to create new native thread](https://www.baeldung.com/java-outofmemoryerror-unable-to-create-new-native-thread)
- [View Bytecode of a Class File in Java](https://www.baeldung.com/java-class-view-bytecode)
- More articles: [[next -->]](/core-java-modules/core-java-jvm-2)
To run the code for the Instrumentation: https://www.baeldung.com/java-instrumentation article:
1- build the module
2- run the module 3 times to build the 3 jars:
mvn install -PbuildAgentLoader
mvn install -PbuildApplication
mvn install -PbuildAgent
3- update the commands in the article with the exact names of the jars generated in the target folder
4- update the path in the AgentLoader class with the path of the agent on your system

View File

@ -57,6 +57,11 @@
<artifactId>jol-core</artifactId>
<version>${jol-core.version}</version>
</dependency>
<dependency> <!-- needed to bridge to slf4j for projects that use the log4j APIs directly -->
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>
<version>${org.slf4j.version}</version>
</dependency>
</dependencies>
<properties>
@ -66,5 +71,114 @@
<asm.version>8.0.1</asm.version>
<bcel.version>6.5.0</bcel.version>
</properties>
<profiles>
<!-- java instrumentation profiles to build jars -->
<profile>
<id>buildAgentLoader</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>jar</goal>
</goals>
<configuration>
<classifier>agentLoader</classifier>
<classesDirectory>target/classes</classesDirectory>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>com.baeldung.instrumentation.application.Launcher</mainClass>
</manifest>
<manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
</archive>
<includes>
<include>com/baeldung/instrumentation/application/AgentLoader.class</include>
<include>com/baeldung/instrumentation/application/Launcher.class</include>
</includes>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>buildApplication</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>jar</goal>
</goals>
<configuration>
<classifier>application</classifier>
<classesDirectory>target/classes</classesDirectory>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>com.baeldung.instrumentation.application.Launcher</mainClass>
</manifest>
<manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
</archive>
<includes>
<include>com/baeldung/instrumentation/application/MyAtm.class</include>
<include>com/baeldung/instrumentation/application/MyAtmApplication.class</include>
<include>com/baeldung/instrumentation/application/Launcher.class</include>
</includes>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>buildAgent</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>jar</goal>
</goals>
<configuration>
<classifier>agent</classifier>
<classesDirectory>target/classes</classesDirectory>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>com.baeldung.instrumentation.application.Launcher</mainClass>
</manifest>
<manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
</archive>
<includes>
<include>com/baeldung/instrumentation/agent/AtmTransformer.class</include>
<include>com/baeldung/instrumentation/agent/MyInstrumentationAgent.class</include>
</includes>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>

View File

@ -0,0 +1,5 @@
Agent-Class: com.baeldung.instrumentation.agent.MyInstrumentationAgent
Can-Redefine-Classes: true
Can-Retransform-Classes: true
Premain-Class: com.baeldung.instrumentation.agent.MyInstrumentationAgent
Main-Class: com.baeldung.instrumentation.application.Launcher

View File

@ -0,0 +1,29 @@
package com.baeldung.truststore;
import org.junit.Test;
import org.junit.jupiter.api.Assertions;
import java.io.IOException;
import java.security.InvalidAlgorithmParameterException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.PKIXParameters;
public class TrustStoreUnitTest {
@Test
public void whenOpeningTrustStore_thenExceptionIsThrown() throws Exception {
KeyStore keyStore = getKeyStore();
InvalidAlgorithmParameterException invalidAlgorithmParameterException =
Assertions.assertThrows(InvalidAlgorithmParameterException.class, () -> new PKIXParameters(keyStore));
Assertions.assertEquals("the trustAnchors parameter must be non-empty", invalidAlgorithmParameterException.getMessage());
}
private KeyStore getKeyStore() throws CertificateException, NoSuchAlgorithmException, IOException, KeyStoreException {
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(null, "changeIt".toCharArray());
return ks;
}
}

View File

@ -0,0 +1,2 @@
FROM nginx:latest
COPY nginx.conf /etc/nginx/nginx.conf

View File

@ -0,0 +1,8 @@
events {}
http {
server {
listen 80;
index index.html;
}
}

View File

@ -0,0 +1,3 @@
FROM nginx:latest
COPY sample-site/html/* /etc/nginx/html/
COPY config/nginx.conf /etc/nginx/nginx.conf

View File

@ -0,0 +1,2 @@
FROM sample-site-base:latest
COPY html/* /etc/nginx/html/

View File

@ -0,0 +1,3 @@
FROM nginx:latest
COPY html/* /etc/nginx/html/
COPY config/nginx.conf /etc/nginx/nginx.conf

View File

@ -0,0 +1,6 @@
mkdir tmp-context
cp -R ../html tmp-context/
cp -R ../../config tmp-context/
cp Dockerfile-script tmp-context/Dockerfile
docker build -t sample-site:latest tmp-context
rm -rf tmp-context

View File

@ -0,0 +1,10 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Sample Site</title>
</head>
<body>
<h2>Welcome to the first page of the site</h2>
</body>
</html>

View File

@ -0,0 +1,12 @@
plugins {
id 'java'
}
description = 'gradle-source-vs-target-compatibility'
group 'com.baeldung'
java {
sourceCompatibility = "1.6"
targetCompatibility = "1.8"
}

View File

@ -0,0 +1,9 @@
package com.baeldung.helloworld;
public class HelloWorldApp {
public static void main(String[] args) {
System.out.println("Hello World!");
}
}

View File

@ -6,5 +6,6 @@ include 'greeter'
include 'gradletaskdemo'
include 'junit5'
include 'gradle-employee-app'
include 'gradle-source-vs-target-compatibility'
println 'This will be executed during the initialization phase.'

View File

@ -0,0 +1,59 @@
package com.baeldung.map.invert;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.stream.Collectors;
public class InvertHashMapExample {
public static void main(String[] args) {
Map<String, Integer> map = new HashMap<>();
map.put("first", 1);
map.put("second", 2);
System.out.println(map);
invertMapUsingForLoop(map);
invertMapUsingStreams(map);
invertMapUsingMapper(map);
map.put("two", 2);
invertMapUsingGroupingBy(map);
}
public static <V, K> Map<V, K> invertMapUsingForLoop(Map<K, V> map) {
Map<V, K> inversedMap = new HashMap<V, K>();
for (Entry<K, V> entry : map.entrySet()) {
inversedMap.put(entry.getValue(), entry.getKey());
}
System.out.println(inversedMap);
return inversedMap;
}
public static <V, K> Map<V, K> invertMapUsingStreams(Map<K, V> map) {
Map<V, K> inversedMap = map.entrySet()
.stream()
.collect(Collectors.toMap(Entry::getValue, Entry::getKey));
System.out.println(inversedMap);
return inversedMap;
}
public static <K, V> Map<V, K> invertMapUsingMapper(Map<K, V> sourceMap) {
Map<V, K> inversedMap = sourceMap.entrySet()
.stream()
.collect(Collectors.toMap(Entry::getValue, Entry::getKey, (oldValue, newValue) -> oldValue));
System.out.println(inversedMap);
return inversedMap;
}
public static <V, K> Map<V, List<K>> invertMapUsingGroupingBy(Map<K, V> map) {
Map<V, List<K>> inversedMap = map.entrySet()
.stream()
.collect(Collectors.groupingBy(Map.Entry::getValue, Collectors.mapping(Map.Entry::getKey, Collectors.toList())));
System.out.println(inversedMap);
return inversedMap;
}
}

View File

@ -0,0 +1,72 @@
package com.baeldung.map.invert;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class InvertHashMapUnitTest {
Map<String, Integer> sourceMap;
@BeforeEach
void setup() {
sourceMap = new HashMap<>();
sourceMap.put("Sunday", 0);
sourceMap.put("Monday", 1);
sourceMap.put("Tuesday", 2);
sourceMap.put("Wednesday", 3);
sourceMap.put("Thursday", 4);
sourceMap.put("Friday", 5);
sourceMap.put("Saturday", 6);
}
@Test
void givenSourceMap_whenUsingForLoop_returnsInvertedMap() {
Map<Integer, String> inversedMap = InvertHashMapExample.invertMapUsingForLoop(sourceMap);
assertNotNull(inversedMap);
assertEquals(sourceMap.size(), inversedMap.size());
assertEquals("Monday", inversedMap.get(1));
}
@Test
void givenSourceMap_whenUsingStreams_returnsInvertedMap() {
Map<Integer, String> inversedMap = InvertHashMapExample.invertMapUsingStreams(sourceMap);
assertNotNull(inversedMap);
assertEquals(sourceMap.size(), inversedMap.size());
assertEquals("Monday", inversedMap.get(1));
}
@Test
void givenSourceMap_whenUsingMapper_returnsInvertedMap() {
Map<Integer, String> inversedMap = InvertHashMapExample.invertMapUsingMapper(sourceMap);
assertNotNull(inversedMap);
assertEquals(sourceMap.size(), inversedMap.size());
assertEquals("Monday", inversedMap.get(1));
}
@Test
void givenSourceMapWithDuplicateValues_whenUsingGroupBy_returnsInvertedMap() {
sourceMap.put("MONDAY", 1);
Map<Integer, List<String>> inversedMap = InvertHashMapExample.invertMapUsingGroupingBy(sourceMap);
assertNotNull(inversedMap);
assertNotEquals(sourceMap.size(), inversedMap.size()); // duplicate keys are merged now
assertEquals(2, inversedMap.get(1).size());
assertTrue(inversedMap.get(1).contains("Monday"));
assertTrue(inversedMap.get(1).contains("MONDAY"));
}
}

View File

@ -0,0 +1,21 @@
#include "com_baeldung_jni_RegisterNativesHelloWorldJNI.h"
#include <iostream>
JNIEXPORT jstring JNICALL hello (JNIEnv* env, jobject thisObject) {
std::string hello = "Hello from registered native C++ !!";
std::cout << hello << std::endl;
return env->NewStringUTF(hello.c_str());
}
static JNINativeMethod methods[] = {
{"sayHello", "()Ljava/lang/String;", (void*) &hello },
};
JNIEXPORT void JNICALL Java_com_baeldung_jni_RegisterNativesHelloWorldJNI_register (JNIEnv* env, jobject thsObject) {
jclass clazz = env->FindClass("com/baeldung/jni/RegisterNativesHelloWorldJNI");
(env)->RegisterNatives(clazz, methods, sizeof(methods)/sizeof(methods[0]));
}

View File

@ -0,0 +1,29 @@
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_baeldung_jni_RegisterNativesHelloWorldJNI */
#ifndef _Included_com_baeldung_jni_RegisterNativesHelloWorldJNI
#define _Included_com_baeldung_jni_RegisterNativesHelloWorldJNI
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_baeldung_jni_RegisterNativesHelloWorldJNI
* Method: sayHello
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_baeldung_jni_RegisterNativesHelloWorldJNI_sayHello
(JNIEnv *, jobject);
/*
* Class: com_baeldung_jni_RegisterNativesHelloWorldJNI
* Method: register
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_com_baeldung_jni_RegisterNativesHelloWorldJNI_register
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif

3
java-native/src/main/cpp/generateNativeLibMac.sh Normal file → Executable file
View File

@ -3,4 +3,5 @@
g++ -c -fPIC -I${JAVA_HOME}/include -I${JAVA_HOME}/include/darwin com_baeldung_jni_HelloWorldJNI.cpp -o com_baeldung_jni_HelloWorldJNI.o
g++ -c -fPIC -I${JAVA_HOME}/include -I${JAVA_HOME}/include/darwin com_baeldung_jni_ExampleParametersJNI.cpp -o com_baeldung_jni_ExampleParametersJNI.o
g++ -c -fPIC -I${JAVA_HOME}/include -I${JAVA_HOME}/include/darwin com_baeldung_jni_ExampleObjectsJNI.cpp -o com_baeldung_jni_ExampleObjectsJNI.o
g++ -dynamiclib -o ../../../native/macos/libnative.dylib com_baeldung_jni_HelloWorldJNI.o com_baeldung_jni_ExampleParametersJNI.o com_baeldung_jni_ExampleObjectsJNI.o -lc
g++ -c -fPIC -I${JAVA_HOME}/include -I${JAVA_HOME}/include/darwin com_baeldung_jni_RegisterNativesHelloWorldJNI.cpp -o com_baeldung_jni_RegisterNativesHelloWorldJNI.o
g++ -dynamiclib -o ../../../native/macos/libnative.dylib com_baeldung_jni_HelloWorldJNI.o com_baeldung_jni_ExampleParametersJNI.o com_baeldung_jni_ExampleObjectsJNI.o com_baeldung_jni_RegisterNativesHelloWorldJNI.o -lc

View File

@ -0,0 +1,18 @@
package com.baeldung.jni;
public class RegisterNativesHelloWorldJNI {
static {
System.loadLibrary("native");
}
public static void main(String[] args) {
RegisterNativesHelloWorldJNI helloWorldJNI = new RegisterNativesHelloWorldJNI();
helloWorldJNI.register();
helloWorldJNI.sayHello();
}
public native String sayHello();
public native void register();
}

View File

@ -0,0 +1,26 @@
package com.baeldung.jni.registernatives;
import com.baeldung.jni.RegisterNativesHelloWorldJNI;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
public class JNIRegisterNativesManualTest {
@Before
public void setup() {
System.loadLibrary("native");
}
@Test
public void whenRegisteredNativeHelloWorld_thenOutputIsAsExpected() {
RegisterNativesHelloWorldJNI helloWorld = new RegisterNativesHelloWorldJNI();
helloWorld.register();
String helloFromNative = helloWorld.sayHello();
assertNotNull(helloFromNative);
assertTrue(helloFromNative.equals("Hello from registered native C++ !!"));
}
}

View File

@ -24,7 +24,7 @@
</dependencies>
<properties>
<spring.version>5.3.13</spring.version>
<spring.version>5.3.16</spring.version>
<spring-security.version>5.6.0</spring-security.version>
<spring-boot-starter-test.version>1.5.10.RELEASE</spring-boot-starter-test.version>
</properties>

View File

@ -0,0 +1,47 @@
package com.baeldung.hibernate.scalarmethod;
import java.util.List;
import org.hibernate.Session;
import org.hibernate.type.StandardBasicTypes;
public class HibernateScalarExample {
private Session session;
public HibernateScalarExample(Session session) {
this.session = session;
}
public List<Object[]> fetchColumnWithNativeQuery() {
return session.createNativeQuery("SELECT * FROM Student student")
.list();
}
public List<Object[]> fetchColumnWithScalar() {
return session.createNativeQuery("SELECT * FROM Student student")
.addScalar("studentId", StandardBasicTypes.LONG)
.addScalar("name", StandardBasicTypes.STRING)
.addScalar("age", StandardBasicTypes.INTEGER)
.list();
}
public List<String> fetchLimitedColumnWithScalar() {
return session.createNativeQuery("SELECT * FROM Student student")
.addScalar("name", StandardBasicTypes.STRING)
.list();
}
public List<Object[]> fetchColumnWithOverloadedScalar() {
return session.createNativeQuery("SELECT * FROM Student student")
.addScalar("name", StandardBasicTypes.STRING)
.addScalar("age")
.list();
}
public Integer fetchAvgAgeWithScalar() {
return (Integer) session.createNativeQuery("SELECT AVG(age) as avgAge FROM Student student")
.addScalar("avgAge")
.uniqueResult();
}
}

View File

@ -0,0 +1,83 @@
package com.baeldung.hibernate.scalarmethod;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.io.IOException;
import java.util.List;
import java.util.Random;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import com.baeldung.hibernate.HibernateUtil;
import com.baeldung.hibernate.pojo.Student;
public class HibernateScalarExampleUnitTest {
private static Session session;
private static Transaction transaction;
private static final int DATA_SIZE = 50000;
private static HibernateScalarExample scalarExample;
@BeforeClass
public static void setUp() throws IOException {
session = HibernateUtil.getSessionFactory().openSession();
transaction = session.beginTransaction();
scalarExample = new HibernateScalarExample(session);
session.createNativeQuery("delete from Student").executeUpdate();
for (int i = 0; i < DATA_SIZE; i++) {
Student student = new Student("John-" + i, generateRandomAge(5, 24));
session.persist(student);
}
transaction.commit();
transaction = session.beginTransaction();
}
@AfterClass
public static void tearDown() {
transaction.rollback();
session.close();
}
@Test
public void givenNativeQuery_whenNoScalarUsed_ThenFetchAll() {
List<Object[]> list = scalarExample.fetchColumnWithNativeQuery();
assertEquals(DATA_SIZE, list.size());
}
@Test
public void givenNativeQuery_whenScalarUsed_ThenFetchAll() {
List<Object[]> list = scalarExample.fetchColumnWithScalar();
assertEquals(DATA_SIZE, list.size());
}
@Test
public void givenNativeQuery_whenScalarUsed_ThenFetchLimitedColumns() {
List<String> list = scalarExample.fetchLimitedColumnWithScalar();
for (String colValue : list) {
assertTrue(colValue.startsWith("John"));
}
}
@Test
public void givenNativeQuery_whenScalarUsedForSingleResult_ThenSingleValueReturned() {
List<Object[]> list = scalarExample.fetchColumnWithOverloadedScalar();
for (Object[] colArray : list) {
assertEquals(2, colArray.length);
}
}
@Test
public void whenScalarUsedForAvgAge_ThenSingleValueReturned() {
Integer avgAge = scalarExample.fetchAvgAgeWithScalar();
assertEquals(true, (avgAge >= 5 && avgAge <= 24));
}
private static int generateRandomAge(int min, int max) {
return new Random().nextInt(max - min + 1) + min;
}
}

View File

@ -1,3 +1,4 @@
### Relevant Articles:
- [Configure and Use Multiple DataSources in Spring Boot](https://www.baeldung.com/spring-boot-configure-multiple-datasources)
- [Introduction to Spring Data JDBC](https://www.baeldung.com/spring-data-jdbc-intro)

View File

@ -51,6 +51,7 @@
<!-- <module>spring-boot-keycloak</module> --> <!-- Fixing under JAVA-8271 -->
<module>spring-boot-libraries</module>
<module>spring-boot-libraries-2</module>
<module>spring-boot-libraries-comparison</module>
<module>spring-boot-logging-log4j2</module>
<module>spring-boot-multiple-datasources</module>
<module>spring-boot-mvc</module>

View File

@ -1,5 +1,6 @@
### Relevant Articles:
- [HttpMessageNotWritableException: No Converter for [class …] With Preset Content-Type](https://www.baeldung.com/spring-no-converter-with-preset)
- [Spring Boot: Customize the Jackson ObjectMapper](https://www.baeldung.com/spring-boot-customize-jackson-objectmapper)
- [“HttpMessageNotWritableException: No converter found for return value of type”](https://www.baeldung.com/spring-no-converter-found)
- [Creating a Read-Only Repository with Spring Data](https://www.baeldung.com/spring-data-read-only-repository)

View File

@ -0,0 +1,7 @@
## Spring Boot Libraries
This module contains articles about various Spring Boot libraries Comparison
### Relevant Articles:
- [GraphQL vs REST](https://www.baeldung.com/graphql-vs-rest/)

View File

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>spring-boot-libraries-comparison</artifactId>
<parent>
<groupId>com.baeldung.spring-boot-modules</groupId>
<artifactId>spring-boot-modules</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.graphql-java</groupId>
<artifactId>graphql-spring-boot-starter</artifactId>
<version>${graphql-spring-boot-starter.version}</version>
</dependency>
<dependency>
<groupId>com.graphql-java</groupId>
<artifactId>graphql-java-tools</artifactId>
<version>${graphql-java-tools.version}</version>
</dependency>
<dependency>
<groupId>com.graphql-java</groupId>
<artifactId>graphiql-spring-boot-starter</artifactId>
<version>${graphql-spring-boot-starter.version}</version>
</dependency>
</dependencies>
<properties>
<graphql-spring-boot-starter.version>5.0.2</graphql-spring-boot-starter.version>
<graphql-java-tools.version>5.2.4</graphql-java-tools.version>
</properties>
</project>

View File

@ -0,0 +1,19 @@
package com.baeldung.graphqlvsrest;
import com.baeldung.graphqlvsrest.configuration.GraphqlConfiguration;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
import org.springframework.context.annotation.Import;
@SpringBootApplication
@Import(GraphqlConfiguration.class)
@EnableAutoConfiguration(exclude = {SecurityAutoConfiguration.class})
public class GraphqlVsRestApplication {
public static void main(String[] args) {
SpringApplication.run(GraphqlVsRestApplication.class, args);
}
}

View File

@ -0,0 +1,35 @@
package com.baeldung.graphqlvsrest.configuration;
import com.baeldung.graphqlvsrest.repository.OrderRepository;
import com.baeldung.graphqlvsrest.resolver.Mutation;
import com.baeldung.graphqlvsrest.resolver.ProductResolver;
import com.baeldung.graphqlvsrest.resolver.Query;
import com.baeldung.graphqlvsrest.repository.ProductRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class GraphqlConfiguration {
@Autowired
ProductRepository productRepository;
@Autowired
OrderRepository orderRepository;
@Bean
public Query query() {
return new Query(productRepository);
}
@Bean
public ProductResolver productResolver(){
return new ProductResolver(orderRepository);
}
@Bean
public Mutation mutation() {
return new Mutation(productRepository);
}
}

View File

@ -0,0 +1,25 @@
package com.baeldung.graphqlvsrest.controller;
import com.baeldung.graphqlvsrest.entity.Order;
import com.baeldung.graphqlvsrest.entity.Product;
import com.baeldung.graphqlvsrest.model.ProductModel;
import com.baeldung.graphqlvsrest.repository.OrderRepository;
import com.baeldung.graphqlvsrest.repository.ProductRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Pageable;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("order")
public class OrderController {
@Autowired
OrderRepository orderRepository;
@GetMapping()
public List<Order> getOrders(@RequestParam("product-id") Integer productId){
return orderRepository.getOrdersByProduct(productId);
}
}

View File

@ -0,0 +1,38 @@
package com.baeldung.graphqlvsrest.controller;
import com.baeldung.graphqlvsrest.entity.Product;
import com.baeldung.graphqlvsrest.model.ProductModel;
import com.baeldung.graphqlvsrest.repository.ProductRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Pageable;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("product")
public class ProductController {
@Autowired
ProductRepository productRepository;
@GetMapping
public List<Product> getProducts(Pageable pageable){
return productRepository.getProducts(pageable.getPageSize(), pageable.getPageNumber());
}
@GetMapping("/{product-id}")
public Product getProducts(@PathVariable("product-id") Integer productId){
return productRepository.getProduct(productId);
}
@PostMapping
public Product save(@RequestBody ProductModel productModel){
return productRepository.save(productModel);
}
@PutMapping("/{product-id}")
public Product update(@PathVariable("product-id") Integer productId, @RequestBody ProductModel productModel){
return productRepository.update(productId, productModel);
}
}

View File

@ -0,0 +1,58 @@
package com.baeldung.graphqlvsrest.entity;
public class Order {
private Integer id;
private Integer product_id;
private String customer_uuid;
private String status;
private String address;
private String creation_date;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getProduct_id() {
return product_id;
}
public void setProduct_id(Integer product_id) {
this.product_id = product_id;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getCustomer_uuid() {
return customer_uuid;
}
public void setCustomer_uuid(String customer_uuid) {
this.customer_uuid = customer_uuid;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getCreation_date() {
return creation_date;
}
public void setCreation_date(String creation_date) {
this.creation_date = creation_date;
}
}

View File

@ -0,0 +1,115 @@
package com.baeldung.graphqlvsrest.entity;
import com.baeldung.graphqlvsrest.model.ProductModel;
import java.util.List;
public class Product {
private Integer id;
private String name;
private String description;
private String status;
private String currency;
private Double price;
private List<String> image_url;
private List<String> video_url;
private Integer stock;
private Float average_rating;
public Product(Integer id, ProductModel productModel) {
this.id = id;
this.name = productModel.getName();
this.description = productModel.getDescription();
this.currency = productModel.getCurrency();
this.price = productModel.getPrice();
this.stock = productModel.getStock();
this.image_url = productModel.getImage_url();
this.video_url = productModel.getVideo_url();
this.average_rating = 0F;
this.status = productModel.getStatus();
}
public Product(){
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getCurrency() {
return currency;
}
public void setCurrency(String currency) {
this.currency = currency;
}
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
public List<String> getImage_url() {
return image_url;
}
public void setImage_url(List<String> image_url) {
this.image_url = image_url;
}
public List<String> getVideo_url() {
return video_url;
}
public void setVideo_url(List<String> video_url) {
this.video_url = video_url;
}
public Integer getStock() {
return stock;
}
public void setStock(Integer stock) {
this.stock = stock;
}
public Float getAverage_rating() {
return average_rating;
}
public void setAverage_rating(Float average_rating) {
this.average_rating = average_rating;
}
}

View File

@ -0,0 +1,92 @@
package com.baeldung.graphqlvsrest.model;
import java.util.List;
public class ProductModel {
private String name;
private String description;
private String status;
private String currency;
private Double price;
private List<String> image_url;
private List<String> video_url;
private Integer stock;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getCurrency() {
return currency;
}
public void setCurrency(String currency) {
this.currency = currency;
}
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
public List<String> getImage_url() {
return image_url;
}
public void setImage_url(List<String> image_url) {
this.image_url = image_url;
}
public List<String> getVideo_url() {
return video_url;
}
public void setVideo_url(List<String> video_url) {
this.video_url = video_url;
}
public Integer getStock() {
return stock;
}
public void setStock(Integer stock) {
this.stock = stock;
}
@Override
public String toString() {
return "ProductModel{" +
"name='" + name + '\'' +
", description='" + description + '\'' +
", status='" + status + '\'' +
", currency='" + currency + '\'' +
", price=" + price +
", image_url=" + image_url +
", video_url=" + video_url +
", stock=" + stock +
'}';
}
}

View File

@ -0,0 +1,11 @@
package com.baeldung.graphqlvsrest.repository;
import com.baeldung.graphqlvsrest.entity.Order;
import com.baeldung.graphqlvsrest.entity.Product;
import com.baeldung.graphqlvsrest.model.ProductModel;
import java.util.List;
public interface OrderRepository {
List<Order> getOrdersByProduct(Integer productId);
}

View File

@ -0,0 +1,14 @@
package com.baeldung.graphqlvsrest.repository;
import com.baeldung.graphqlvsrest.entity.Product;
import com.baeldung.graphqlvsrest.model.ProductModel;
import java.util.List;
public interface ProductRepository {
List<Product> getProducts(Integer pageSize, Integer pageNumber);
Product getProduct(Integer id);
Product save(ProductModel productModel);
Product update(Integer productId, ProductModel productModel);
}

View File

@ -0,0 +1,36 @@
package com.baeldung.graphqlvsrest.repository.impl;
import com.baeldung.graphqlvsrest.entity.Order;
import com.baeldung.graphqlvsrest.repository.OrderRepository;
import org.springframework.stereotype.Repository;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
@Repository
public class OrderRepositoryImpl implements OrderRepository {
private static List<Order> orderList = new ArrayList<>();
public OrderRepositoryImpl() {
for (int i = 1; i <= 100; i++){
Order order = new Order();
order.setId(i);
order.setProduct_id(i%10);
order.setAddress(UUID.randomUUID().toString());
order.setCustomer_uuid(UUID.randomUUID().toString());
order.setCreation_date(new Date(System.currentTimeMillis()).toString());
order.setStatus("Delivered");
orderList.add(order);
}
}
@Override
public List<Order> getOrdersByProduct(Integer productId) {
return orderList.stream().filter(order -> order.getProduct_id().equals(productId)).collect(Collectors.toList());
}
}

View File

@ -0,0 +1,74 @@
package com.baeldung.graphqlvsrest.repository.impl;
import com.baeldung.graphqlvsrest.entity.Product;
import com.baeldung.graphqlvsrest.model.ProductModel;
import com.baeldung.graphqlvsrest.repository.ProductRepository;
import org.springframework.stereotype.Repository;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
@Repository
public class ProductRepositoryImpl implements ProductRepository {
private static List<Product> productList = new ArrayList<>();
public ProductRepositoryImpl() {
for (int i = 1; i <= 10; i++){
Product product = new Product();
product.setId(i);
product.setName(String.format("Product %d", i));
product.setDescription(String.format("Product %d description", i));
product.setCurrency(String.format("Product %d currency", i));
product.setPrice(Double.valueOf(i^2));
product.setStock(10);
product.setAverage_rating(0F);
product.setImage_url(Arrays.asList(String.format("www.baeldung.com/imageurl/%d", i)));
product.setVideo_url(Arrays.asList(String.format("www.baeldung.com/videourl/%d", i)));
productList.add(product);
}
}
@Override
public List<Product> getProducts(Integer pageSize, Integer pageNumber) {
return productList.stream().skip(pageSize*pageNumber).limit(pageSize).collect(Collectors.toList());
}
@Override
public Product getProduct(Integer id) {
return productList.stream().filter(product -> product.getId().equals(id)).findFirst().orElse(null);
}
@Override
public Product save(ProductModel productModel) {
Product product = new Product(productList.size()+1, productModel);
productList.add(product);
return product;
}
@Override
public Product update(Integer productId, ProductModel productModel) {
Product product = getProduct(productId);
if (product != null){
update(product, productModel);
}
return product;
}
private void update(Product product, ProductModel productModel){
if (productModel != null) {
System.out.println(productModel.toString());
Optional.ofNullable(productModel.getName()).ifPresent(product::setName);
Optional.ofNullable(productModel.getDescription()).ifPresent(product::setDescription);
Optional.ofNullable(productModel.getCurrency()).ifPresent(product::setCurrency);
Optional.ofNullable(productModel.getImage_url()).ifPresent(product::setImage_url);
Optional.ofNullable(productModel.getStock()).ifPresent(product::setStock);
Optional.ofNullable(productModel.getStatus()).ifPresent(product::setStatus);
Optional.ofNullable(productModel.getVideo_url()).ifPresent(product::setVideo_url);
Optional.ofNullable(productModel.getPrice()).ifPresent(product::setPrice);
}
}
}

View File

@ -0,0 +1,22 @@
package com.baeldung.graphqlvsrest.resolver;
import com.baeldung.graphqlvsrest.entity.Product;
import com.baeldung.graphqlvsrest.model.ProductModel;
import com.baeldung.graphqlvsrest.repository.ProductRepository;
import com.coxautodev.graphql.tools.GraphQLMutationResolver;
public class Mutation implements GraphQLMutationResolver {
private ProductRepository productRepository;
public Mutation(ProductRepository productRepository){
this.productRepository = productRepository;
}
public Product saveProduct(ProductModel productModel) {
return productRepository.save(productModel);
}
public Product updateProduct(Integer productId, ProductModel productModel) {
return productRepository.update(productId, productModel);
}
}

View File

@ -0,0 +1,18 @@
package com.baeldung.graphqlvsrest.resolver;
import com.baeldung.graphqlvsrest.entity.Order;
import com.baeldung.graphqlvsrest.entity.Product;
import com.baeldung.graphqlvsrest.repository.OrderRepository;
import com.coxautodev.graphql.tools.GraphQLResolver;
import java.util.List;
public class ProductResolver implements GraphQLResolver<Product> {
private OrderRepository orderRepository;
public ProductResolver(OrderRepository orderRepository){
this.orderRepository = orderRepository;
}
public List<Order> getOrders(Product product){
return orderRepository.getOrdersByProduct(product.getId());
}
}

View File

@ -0,0 +1,27 @@
package com.baeldung.graphqlvsrest.resolver;
import com.baeldung.graphqlvsrest.entity.Order;
import com.baeldung.graphqlvsrest.entity.Product;
import com.baeldung.graphqlvsrest.repository.OrderRepository;
import com.baeldung.graphqlvsrest.repository.ProductRepository;
import com.coxautodev.graphql.tools.GraphQLQueryResolver;
import java.util.List;
public class Query implements GraphQLQueryResolver {
private ProductRepository productRepository;
public Query(ProductRepository productRepository){
this.productRepository = productRepository;
}
public List<Product> getProducts(int pageSize, int pageNumber) {
return productRepository.getProducts(pageSize, pageNumber);
}
public Product getProduct(int id) {
return productRepository.getProduct(id);
}
}

View File

@ -0,0 +1,57 @@
type Product {
id: ID
name: String!
description: String
status: String
currency: String!
price: Float
image_url: [String]
video_url: [String]
stock: Int
average_rating: Float
orders:[Order]
}
type Order{
id:ID
product_id:Int
customer_uuid:String
address:String
status:String
creation_date:String
}
input ProductModel {
name: String!
description: String
status: String
currency: String!
price: Float
image_url: [String]
video_url: [String]
stock: Int
}
input ProductUpdateModel {
name: String
description: String
status: String
currency: String
price: Float
image_url: [String]
video_url: [String]
stock: Int
}
# The Root Query for the application
type Query {
products(size: Int, page: Int): [Product]!
product(id: Int): Product!
}
# The Root Mutation for the application
type Mutation {
saveProduct(product: ProductModel) : Product!
updateProduct(id: Int, product: ProductUpdateModel) : Product!
}

View File

@ -0,0 +1,13 @@
package com.baeldung.antmatchers;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class AntMatchersExampleApplication {
public static void main(String[] args) {
SpringApplication.run(AntMatchersExampleApplication.class, args);
}
}

View File

@ -0,0 +1,39 @@
package com.baeldung.antmatchers.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("admin").password(passwordEncoder().encode("password")).roles("USER", "ADMIN")
.and()
.withUser("user").password(passwordEncoder().encode("password")).roles("USER");
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/products/**").permitAll()
.and()
.authorizeRequests()
.antMatchers("/customers/**").hasRole("ADMIN")
.anyRequest().authenticated()
.and()
.httpBasic();
}
}

View File

@ -0,0 +1,15 @@
package com.baeldung.antmatchers.controllers;
import com.baeldung.antmatchers.dtos.Customer;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class CustomerController {
@GetMapping("/customers/{id}")
public Customer getCustomerById(@PathVariable("id") String id) {
return new Customer("Customer 1", "Address 1", "Phone 1");
}
}

View File

@ -0,0 +1,21 @@
package com.baeldung.antmatchers.controllers;
import com.baeldung.antmatchers.dtos.Product;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@RestController
public class ProductController {
@GetMapping("/products")
public List<Product> getProducts() {
return new ArrayList<>(Arrays.asList(
new Product("Product 1", "Description 1", 1.0),
new Product("Product 2", "Description 2", 2.0)
));
}
}

View File

@ -0,0 +1,39 @@
package com.baeldung.antmatchers.dtos;
import java.io.Serializable;
public class Customer implements Serializable {
private String name;
private String address;
private String phone;
public Customer(String name, String address, String phone) {
this.name = name;
this.address = address;
this.phone = phone;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
}

View File

@ -0,0 +1,39 @@
package com.baeldung.antmatchers.dtos;
import java.io.Serializable;
public class Product implements Serializable {
private String name;
private String description;
private double price;
public Product(String name, String description, double price) {
this.name = name;
this.description = description;
this.price = price;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
}

View File

@ -0,0 +1,38 @@
package com.baeldung.antmatchers.controllers;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@RunWith(SpringRunner.class)
@WebMvcTest(value = CustomerController.class)
class CustomerControllerIntegrationTest {
@Autowired
private MockMvc mockMvc;
@Test
void getCustomerByIdUnauthorized() throws Exception {
mockMvc.perform(get("/customers/1")).andExpect(status().isUnauthorized());
}
@Test
void getCustomerByIdForbidden() throws Exception {
mockMvc.perform(get("/customers/1").with(user("user").roles("USER")))
.andExpect(status().isForbidden());
}
@Test
void getCustomerByIdOk() throws Exception {
mockMvc.perform(get("/customers/1").with(user("admin").roles("ADMIN")))
.andExpect(status().isOk());
}
}

View File

@ -0,0 +1,25 @@
package com.baeldung.antmatchers.controllers;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@RunWith(SpringRunner.class)
@WebMvcTest(value = ProductController.class)
class ProductControllerIntegrationTest {
@Autowired
private MockMvc mockMvc;
@Test
void getProducts() throws Exception {
mockMvc.perform(get("/products"))
.andExpect(status().isOk());
}
}

View File

@ -1,57 +0,0 @@
{
"swagger" : "2.0",
"info" : {
"description" : "This is a Baeldung Document Enum Sample Code",
"version" : "v1",
"title" : "Baeldung - Document Enum",
"contact" : {
"name" : "Parikshit Murria",
"email" : "pmurria@baeldung.com"
},
"license" : {
"name" : "Apache 2.0",
"url" : "https://www.apache.org/licenses/LICENSE-2.0.html"
}
},
"host" : "baeldung.com",
"basePath" : "/api",
"schemes" : [ "http", "https" ],
"paths" : {
"/hire" : {
"post" : {
"summary" : "This method is used to hire employee with a specific role",
"description" : "",
"operationId" : "hireEmployee",
"produces" : [ "application/json" ],
"parameters" : [ {
"in" : "body",
"name" : "body",
"description" : "role",
"required" : true,
"schema" : {
"$ref" : "#/definitions/Employee"
}
} ],
"responses" : {
"200" : {
"description" : "successful operation",
"schema" : {
"type" : "string"
}
}
}
}
}
},
"definitions" : {
"Employee" : {
"type" : "object",
"properties" : {
"role" : {
"type" : "string",
"enum" : [ "Engineer", "Clerk", "Driver", "Janitor" ]
}
}
}
}
}

View File

@ -63,7 +63,7 @@
<name>Apache 2.0</name>
</license>
</info>
<swaggerDirectory>generated/swagger-ui</swaggerDirectory>
<swaggerDirectory>${basedir}/target/swagger-ui</swaggerDirectory>
</apiSource>
</apiSources>
</configuration>

View File

@ -177,5 +177,21 @@
</plugins>
</build>
</profile>
<profile>
<id>gateway-url-rewrite</id>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>com.baeldung.springcloudgateway.rewrite.URLRewriteGatewayApplication</mainClass>
<jvmArguments>-Dspring.profiles.active=url-rewrite</jvmArguments>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>

View File

@ -0,0 +1,25 @@
/**
*
*/
package com.baeldung.springcloudgateway.rewrite;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import reactor.core.publisher.Mono;
/**
* @author Baeldung
*
*/
@SpringBootApplication
public class URLRewriteGatewayApplication {
public static void main(String[] args) {
new SpringApplicationBuilder(URLRewriteGatewayApplication.class)
.profiles("url-rewrite")
.run(args);
}
}

View File

@ -0,0 +1,43 @@
package com.baeldung.springcloudgateway.rewrite.routes;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.http.server.reactive.ServerHttpRequest;
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR;
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.addOriginalRequestUrl;
import java.util.Random;
@Configuration
@Profile("url-rewrite")
public class DynamicRewriteRoute {
@Value("${rewrite.backend.uri}")
private String backendUri;
private static Random rnd = new Random();
@Bean
public RouteLocator dynamicZipCodeRoute(RouteLocatorBuilder builder) {
return builder.routes()
.route("dynamicRewrite", r ->
r.path("/v2/zip/**")
.filters(f -> f.filter((exchange, chain) -> {
ServerHttpRequest req = exchange.getRequest();
addOriginalRequestUrl(exchange, req.getURI());
String path = req.getURI().getRawPath();
String newPath = path.replaceAll(
"/v2/zip/(?<zipcode>.*)",
"/api/zip/${zipcode}-" + String.format("%03d", rnd.nextInt(1000)));
ServerHttpRequest request = req.mutate().path(newPath).build();
exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, request.getURI());
return chain.filter(exchange.mutate().request(request).build());
}))
.uri(backendUri))
.build();
}
}

View File

@ -8,7 +8,7 @@ public class WebFilterGatewayApplication {
public static void main(String[] args) {
new SpringApplicationBuilder(WebFilterGatewayApplication.class)
.profiles("webfilters")
.profiles("url-rewrite")
.run(args);
}

View File

@ -0,0 +1,8 @@
# Enable this profile to disable security
spring:
autoconfigure:
exclude:
- org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration
- org.springframework.boot.actuate.autoconfigure.ManagementSecurityAutoConfiguration
- org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration
- org.springframework.boot.actuate.autoconfigure.security.reactive.ReactiveManagementWebSecurityAutoConfiguration

View File

@ -0,0 +1,11 @@
spring:
cloud:
gateway:
routes:
- id: rewrite_v1
uri: ${rewrite.backend.uri:http://example.com}
predicates:
- Path=/v1/customer/**
filters:
- RewritePath=/v1/customer/(?<segment>.*),/api/$\{segment}

View File

@ -0,0 +1,109 @@
package com.baeldung.springcloudgateway.rewrite;
import static org.junit.Assert.assertTrue;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import org.junit.AfterClass;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.DynamicPropertyRegistry;
import org.springframework.test.context.DynamicPropertySource;
import org.springframework.test.web.reactive.server.WebTestClient;
import com.sun.net.httpserver.HttpServer;
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@ActiveProfiles({ "nosecurity", "url-rewrite" })
class URLRewriteGatewayApplicationLiveTest {
// NOTE for Eclipse users: By default, Eclipse will complain about com.sun.** classes.
// To solve this issue, follow instructions available at the :
// https://stackoverflow.com/questions/13155734/eclipse-cant-recognize-com-sun-net-httpserver-httpserver-package
private static HttpServer mockServer;
private static Logger log = LoggerFactory.getLogger(URLRewriteGatewayApplicationLiveTest.class);
// Create a running HttpServer that echoes back the request URL.
private static HttpServer startTestServer() {
try {
log.info("[I26] Starting mock server");
mockServer = HttpServer.create();
mockServer.bind(new InetSocketAddress(0), 0);
mockServer.createContext("/api", (xchg) -> {
String uri = xchg.getRequestURI()
.toString();
log.info("[I23] Backend called: uri={}", uri);
xchg.getResponseHeaders()
.add("Content-Type", "text/plain");
xchg.sendResponseHeaders(200, 0);
OutputStream os = xchg.getResponseBody();
os.write(uri.getBytes());
os.flush();
os.close();
});
mockServer.start();
InetSocketAddress localAddr = mockServer.getAddress();
log.info("[I36] mock server started: local address={}", localAddr);
return mockServer;
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
// TIP: https://www.baeldung.com/spring-dynamicpropertysource
@DynamicPropertySource
static void registerBackendServer(DynamicPropertyRegistry registry) {
registry.add("rewrite.backend.uri", () -> {
HttpServer s = startTestServer();
return "http://localhost:" + s.getAddress().getPort();
});
}
@AfterClass
public static void stopMockBackend() throws Exception {
log.info("[I40] Shutdown mock http server");
mockServer.stop(5);
}
@LocalServerPort
private int localPort;
@Test
void testWhenApiCall_thenRewriteSuccess(@Autowired WebTestClient webClient) {
webClient.get()
.uri("http://localhost:" + localPort + "/v1/customer/customer1")
.exchange()
.expectBody()
.consumeWith((result) -> {
String body = new String(result.getResponseBody());
log.info("[I99] body={}", body);
assertEquals("/api/customer1", body);
});
}
@Test
void testWhenDslCall_thenRewriteSuccess(@Autowired WebTestClient webClient) {
webClient.get()
.uri("http://localhost:" + localPort + "/v2/zip/123456")
.exchange()
.expectBody()
.consumeWith((result) -> {
String body = new String(result.getResponseBody());
log.info("[I99] body={}", body);
assertTrue(body.matches("/api/zip/123456-\\d{3}"));
});
}
}

View File

@ -48,7 +48,15 @@
<dependency>
<groupId>io.github.openfeign.form</groupId>
<artifactId>feign-form-spring</artifactId>
</dependency>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>

View File

@ -0,0 +1,16 @@
package com.baeldung.cloud.openfeign.client;
import com.baeldung.cloud.openfeign.model.Payment;
import com.baeldung.cloud.openfeign.oauthfeign.OAuthFeignConfig;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import java.util.List;
@FeignClient(name = "payment-client", url = "http://localhost:8081/resource-server-jwt", configuration = OAuthFeignConfig.class)
public interface PaymentClient {
@RequestMapping(value = "/payments", method = RequestMethod.GET)
List<Payment> getPayments();
}

View File

@ -0,0 +1,24 @@
package com.baeldung.cloud.openfeign.controller;
import com.baeldung.cloud.openfeign.client.PaymentClient;
import com.baeldung.cloud.openfeign.model.Payment;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
public class PaymentController {
private final PaymentClient paymentClient;
public PaymentController(PaymentClient paymentClient) {
this.paymentClient = paymentClient;
}
@GetMapping("/payments")
public List<Payment> getPayments() {
List<Payment> payments = paymentClient.getPayments();
return payments;
}
}

View File

@ -0,0 +1,23 @@
package com.baeldung.cloud.openfeign.model;
public class Payment {
private String id;
private double amount;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public double getAmount() {
return amount;
}
public void setAmount(double amount) {
this.amount = amount;
}
}

View File

@ -0,0 +1,19 @@
package com.baeldung.cloud.openfeign.oauthfeign;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@Configuration
public class OAuth2WebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf()
.disable()
.oauth2Client();
http
.authorizeRequests().anyRequest().permitAll();
}
}

View File

@ -0,0 +1,85 @@
package com.baeldung.cloud.openfeign.oauthfeign;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.oauth2.client.OAuth2AuthorizeRequest;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClient;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientManager;
import org.springframework.security.oauth2.client.registration.ClientRegistration;
import java.util.Collection;
import java.util.Collections;
import static java.util.Objects.isNull;
public class OAuthClientCredentialsFeignManager {
private static final Logger logger = LoggerFactory.getLogger(OAuthClientCredentialsFeignManager.class);
private final OAuth2AuthorizedClientManager manager;
private final Authentication principal;
private final ClientRegistration clientRegistration;
public OAuthClientCredentialsFeignManager(OAuth2AuthorizedClientManager manager, ClientRegistration clientRegistration) {
this.manager = manager;
this.clientRegistration = clientRegistration;
this.principal = createPrincipal();
}
private Authentication createPrincipal() {
return new Authentication() {
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return Collections.emptySet();
}
@Override
public Object getCredentials() {
return null;
}
@Override
public Object getDetails() {
return null;
}
@Override
public Object getPrincipal() {
return this;
}
@Override
public boolean isAuthenticated() {
return false;
}
@Override
public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
}
@Override
public String getName() {
return clientRegistration.getClientId();
}
};
}
public String getAccessToken() {
try {
OAuth2AuthorizeRequest oAuth2AuthorizeRequest = OAuth2AuthorizeRequest
.withClientRegistrationId(clientRegistration.getRegistrationId())
.principal(principal)
.build();
OAuth2AuthorizedClient client = manager.authorize(oAuth2AuthorizeRequest);
if (isNull(client)) {
throw new IllegalStateException("client credentials flow on " + clientRegistration.getRegistrationId() + " failed, client is null");
}
return client.getAccessToken().getTokenValue();
} catch (Exception exp) {
logger.error("client credentials error " + exp.getMessage());
}
return null;
}
}

View File

@ -0,0 +1,46 @@
package com.baeldung.cloud.openfeign.oauthfeign;
import feign.RequestInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.oauth2.client.*;
import org.springframework.security.oauth2.client.registration.ClientRegistration;
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
@Configuration
public class OAuthFeignConfig {
public static final String CLIENT_REGISTRATION_ID = "keycloak";
private final OAuth2AuthorizedClientService oAuth2AuthorizedClientService;
private final ClientRegistrationRepository clientRegistrationRepository;
public OAuthFeignConfig(OAuth2AuthorizedClientService oAuth2AuthorizedClientService,
ClientRegistrationRepository clientRegistrationRepository) {
this.oAuth2AuthorizedClientService = oAuth2AuthorizedClientService;
this.clientRegistrationRepository = clientRegistrationRepository;
}
@Bean
public RequestInterceptor requestInterceptor() {
ClientRegistration clientRegistration = clientRegistrationRepository.findByRegistrationId(CLIENT_REGISTRATION_ID);
OAuthClientCredentialsFeignManager clientCredentialsFeignManager =
new OAuthClientCredentialsFeignManager(authorizedClientManager(), clientRegistration);
return requestTemplate -> {
requestTemplate.header("Authorization", "Bearer " + clientCredentialsFeignManager.getAccessToken());
};
}
@Bean
OAuth2AuthorizedClientManager authorizedClientManager() {
OAuth2AuthorizedClientProvider authorizedClientProvider = OAuth2AuthorizedClientProviderBuilder.builder()
.clientCredentials()
.build();
AuthorizedClientServiceOAuth2AuthorizedClientManager authorizedClientManager =
new AuthorizedClientServiceOAuth2AuthorizedClientManager(clientRegistrationRepository, oAuth2AuthorizedClientService);
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
return authorizedClientManager;
}
}

View File

@ -1,3 +1,10 @@
server.port=8085
spring.main.allow-bean-definition-overriding=true
spring.application.name= openfeign
logging.level.com.baeldung.cloud.openfeign.client: DEBUG
feign.hystrix.enabled=true
spring.security.oauth2.client.registration.keycloak.authorization-grant-type=client_credentials
spring.security.oauth2.client.registration.keycloak.client-id=payment-app
spring.security.oauth2.client.registration.keycloak.client-secret=863e9de4-33d4-4471-b35e-f8d2434385bb
spring.security.oauth2.client.provider.keycloak.token-uri=http://localhost:8083/auth/realms/master/protocol/openid-connect/token

View File

@ -0,0 +1,30 @@
package com.baeldung.cloud.openfeign;
import com.baeldung.cloud.openfeign.client.PaymentClient;
import com.baeldung.cloud.openfeign.model.Payment;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.List;
import static org.junit.Assert.assertFalse;
@RunWith(SpringRunner.class)
@SpringBootTest
public class PaymentClientUnitTest {
@Autowired
private PaymentClient paymentClient;
@Test
public void whenGetPayment_thenListPayments() {
List<Payment> payments = paymentClient.getPayments();
assertFalse(payments.isEmpty());
}
}

View File

@ -64,11 +64,6 @@
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-commons</artifactId>
</dependency>
<!-- deployment -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</dependency>
<!-- web -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
@ -154,17 +149,9 @@
</plugin>
<plugin>
<groupId>org.codehaus.cargo</groupId>
<artifactId>cargo-maven2-plugin</artifactId>
<version>${cargo-maven2-plugin.version}</version>
<artifactId>cargo-maven3-plugin</artifactId>
<version>${cargo-maven3-plugin.version}</version>
<configuration>
<wait>true</wait>
<container>
<containerId>jetty8x</containerId>
<type>embedded</type>
<systemProperties>
<!-- <provPersistenceTarget>cargo</provPersistenceTarget> -->
</systemProperties>
</container>
<configuration>
<properties>
<cargo.servlet.port>8082</cargo.servlet.port>
@ -194,15 +181,32 @@
<profiles>
<profile>
<id>live</id>
<id>cargo-integration</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<executions>
<execution>
<phase>integration-test</phase>
<goals>
<goal>test</goal>
</goals>
<configuration>
<excludes>
<exclude>none</exclude>
</excludes>
<includes>
<include>**/*LiveTest.java</include>
</includes>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.cargo</groupId>
<artifactId>cargo-maven2-plugin</artifactId>
<configuration>
<wait>false</wait>
</configuration>
<artifactId>cargo-maven3-plugin</artifactId>
<executions>
<execution>
<id>start-server</id>
@ -232,7 +236,7 @@
<!-- util -->
<javassist.version>3.25.0-GA</javassist.version>
<!-- Maven plugins -->
<cargo-maven2-plugin.version>1.6.1</cargo-maven2-plugin.version>
<cargo-maven3-plugin.version>1.9.9</cargo-maven3-plugin.version>
<apt-maven-plugin.version>1.1.3</apt-maven-plugin.version>
</properties>

View File

@ -0,0 +1,13 @@
package com.baeldung.cargo;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertTrue;
class CargoPluginLiveTest {
@Test
void givenCargoProfile_expectTestRuns() {
assertTrue(true);
}
}