diff --git a/apache-poi-2/README.md b/apache-poi-2/README.md index 2fd0135b11..2c0deec575 100644 --- a/apache-poi-2/README.md +++ b/apache-poi-2/README.md @@ -9,4 +9,6 @@ This module contains articles about Apache POI. - [Numeric Format Using POI](https://www.baeldung.com/apache-poi-numeric-format) - [Microsoft Word Processing in Java with Apache POI](https://www.baeldung.com/java-microsoft-word-with-apache-poi) - [Creating a MS PowerPoint Presentation in Java](https://www.baeldung.com/apache-poi-slideshow) +- [Finding the Last Row in an Excel Spreadsheet From Java](https://www.baeldung.com/java-excel-find-last-row) +- [Setting Formulas in Excel with Apache POI](https://www.baeldung.com/java-apache-poi-set-formulas) - More articles: [[<-- prev]](../apache-poi) diff --git a/apache-poi-2/pom.xml b/apache-poi-2/pom.xml index a46365c63c..30270cd7be 100644 --- a/apache-poi-2/pom.xml +++ b/apache-poi-2/pom.xml @@ -22,7 +22,7 @@ - 5.0.0 + 5.2.0 diff --git a/apache-poi/src/main/java/com/baeldung/poi/excel/setformula/ExcelFormula.java b/apache-poi-2/src/main/java/com/baeldung/poi/excel/setformula/ExcelFormula.java similarity index 88% rename from apache-poi/src/main/java/com/baeldung/poi/excel/setformula/ExcelFormula.java rename to apache-poi-2/src/main/java/com/baeldung/poi/excel/setformula/ExcelFormula.java index f5179b19c9..ccff1fa709 100644 --- a/apache-poi/src/main/java/com/baeldung/poi/excel/setformula/ExcelFormula.java +++ b/apache-poi-2/src/main/java/com/baeldung/poi/excel/setformula/ExcelFormula.java @@ -1,26 +1,25 @@ -package com.baeldung.poi.excel.setformula; - -import org.apache.poi.xssf.usermodel.XSSFCell; -import org.apache.poi.xssf.usermodel.XSSFFormulaEvaluator; -import org.apache.poi.xssf.usermodel.XSSFSheet; -import org.apache.poi.xssf.usermodel.XSSFWorkbook; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; - -public class ExcelFormula { - public double setFormula(String fileLocation, XSSFWorkbook wb, String formula) throws IOException { - XSSFSheet sheet = wb.getSheetAt(0); - int lastCellNum = sheet.getRow(0).getLastCellNum(); - XSSFCell formulaCell = sheet.getRow(0).createCell(lastCellNum); - formulaCell.setCellFormula(formula); - XSSFFormulaEvaluator formulaEvaluator = wb.getCreationHelper().createFormulaEvaluator(); - formulaEvaluator.evaluateFormulaCell(formulaCell); - FileOutputStream fileOut = new FileOutputStream(new File(fileLocation)); - wb.write(fileOut); - wb.close(); - fileOut.close(); - return formulaCell.getNumericCellValue(); - } -} +package com.baeldung.poi.excel.setformula; + +import org.apache.poi.xssf.usermodel.XSSFCell; +import org.apache.poi.xssf.usermodel.XSSFFormulaEvaluator; +import org.apache.poi.xssf.usermodel.XSSFSheet; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; + +import java.io.FileOutputStream; +import java.io.IOException; + +public class ExcelFormula { + public double setFormula(String fileLocation, XSSFWorkbook wb, String formula) throws IOException { + XSSFSheet sheet = wb.getSheetAt(0); + int lastCellNum = sheet.getRow(0).getLastCellNum(); + XSSFCell formulaCell = sheet.getRow(0).createCell(lastCellNum); + formulaCell.setCellFormula(formula); + XSSFFormulaEvaluator formulaEvaluator = wb.getCreationHelper().createFormulaEvaluator(); + formulaEvaluator.evaluateFormulaCell(formulaCell); + FileOutputStream fileOut = new FileOutputStream(fileLocation); + wb.write(fileOut); + wb.close(); + fileOut.close(); + return formulaCell.getNumericCellValue(); + } +} diff --git a/apache-poi/src/main/resources/com/baeldung/poi/excel/setformula/SetFormulaTest.xlsx b/apache-poi-2/src/main/resources/com/baeldung/poi/excel/setformula/SetFormulaTest.xlsx similarity index 100% rename from apache-poi/src/main/resources/com/baeldung/poi/excel/setformula/SetFormulaTest.xlsx rename to apache-poi-2/src/main/resources/com/baeldung/poi/excel/setformula/SetFormulaTest.xlsx diff --git a/apache-poi-2/src/test/java/com/baeldung/poi/excel/lastrow/LastRowUnitTest.java b/apache-poi-2/src/test/java/com/baeldung/poi/excel/lastrow/LastRowUnitTest.java new file mode 100644 index 0000000000..ea838be4ce --- /dev/null +++ b/apache-poi-2/src/test/java/com/baeldung/poi/excel/lastrow/LastRowUnitTest.java @@ -0,0 +1,67 @@ +package com.baeldung.poi.excel.lastrow; + +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.Workbook; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; +import org.junit.Before; +import org.junit.Test; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.nio.file.Paths; + +import static org.junit.jupiter.api.Assertions.*; + +public class LastRowUnitTest { + private static final String FILE_NAME = "lastRowTest.xlsx"; + private String fileLocation; + + @Before + public void setup() throws URISyntaxException { + fileLocation = Paths.get(ClassLoader.getSystemResource(FILE_NAME).toURI()).toString(); + } + + @Test + public void givenExampleGrid_whenGetRow_thenReturnRowObjectIfModified() throws IOException { + Workbook workbook = new XSSFWorkbook(fileLocation); + Sheet sheet = workbook.getSheetAt(0); + + assertEquals(7, sheet.getLastRowNum()); + assertEquals(6, sheet.getPhysicalNumberOfRows()); + + assertNotNull(sheet.getRow(0)); + assertNotNull(sheet.getRow(1)); + assertNotNull(sheet.getRow(2)); + assertNotNull(sheet.getRow(3)); + assertNull(sheet.getRow(4)); + assertNull(sheet.getRow(5)); + assertNotNull(sheet.getRow(6)); + assertNotNull(sheet.getRow(7)); + assertNull(sheet.getRow(8)); + + assertSame(sheet.getRow(7), getLastRowFromSheet(sheet)); + } + + @Test + public void givenEmptySheet_whenGetRow_thenReturnNull() throws IOException { + Workbook workbook = new XSSFWorkbook(fileLocation); + Sheet sheet = workbook.getSheetAt(1); + + assertEquals(-1, sheet.getLastRowNum()); + assertEquals(0, sheet.getPhysicalNumberOfRows()); + + assertNull(sheet.getRow(0)); + + assertSame(sheet.getRow(0), getLastRowFromSheet(sheet)); + } + + public static Row getLastRowFromSheet(Sheet sheet) { + Row lastRow = null; + int lastRowNum = sheet.getLastRowNum(); + if (lastRowNum >= 0) { + lastRow = sheet.getRow(lastRowNum); + } + return lastRow; + } +} diff --git a/apache-poi/src/test/java/com/baeldung/poi/excel/setformula/ExcelFormulaUnitTest.java b/apache-poi-2/src/test/java/com/baeldung/poi/excel/setformula/ExcelFormulaUnitTest.java similarity index 85% rename from apache-poi/src/test/java/com/baeldung/poi/excel/setformula/ExcelFormulaUnitTest.java rename to apache-poi-2/src/test/java/com/baeldung/poi/excel/setformula/ExcelFormulaUnitTest.java index fa5baa37fa..7a0f15b3f7 100644 --- a/apache-poi/src/test/java/com/baeldung/poi/excel/setformula/ExcelFormulaUnitTest.java +++ b/apache-poi-2/src/test/java/com/baeldung/poi/excel/setformula/ExcelFormulaUnitTest.java @@ -3,18 +3,19 @@ package com.baeldung.poi.excel.setformula; import org.apache.poi.ss.util.CellReference; import org.apache.poi.xssf.usermodel.XSSFSheet; import org.apache.poi.xssf.usermodel.XSSFWorkbook; -import org.junit.Assert; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.net.URISyntaxException; import java.nio.file.Paths; +import static org.junit.jupiter.api.Assertions.assertEquals; + class ExcelFormulaUnitTest { - private static String FILE_NAME = "com/baeldung/poi/excel/setformula/SetFormulaTest.xlsx"; + private static final String FILE_NAME = "com/baeldung/poi/excel/setformula/SetFormulaTest.xlsx"; + private String fileLocation; private ExcelFormula excelFormula; @@ -26,7 +27,7 @@ class ExcelFormulaUnitTest { @Test void givenExcelData_whenSetFormula_thenSuccess() throws IOException { - FileInputStream inputStream = new FileInputStream(new File(fileLocation)); + FileInputStream inputStream = new FileInputStream(fileLocation); XSSFWorkbook wb = new XSSFWorkbook(inputStream); XSSFSheet sheet = wb.getSheetAt(0); double resultColumnA = 0; @@ -46,6 +47,6 @@ class ExcelFormulaUnitTest { double resultValue = excelFormula.setFormula(fileLocation, wb, sumFormulaForColumnA + "-" + sumFormulaForColumnB); - Assert.assertEquals(resultColumnA - resultColumnB, resultValue, 0d); + assertEquals(resultColumnA - resultColumnB, resultValue, 0d); } } diff --git a/apache-poi-2/src/test/resources/lastRowTest.xlsx b/apache-poi-2/src/test/resources/lastRowTest.xlsx new file mode 100644 index 0000000000..3980ceb1f2 Binary files /dev/null and b/apache-poi-2/src/test/resources/lastRowTest.xlsx differ diff --git a/apache-poi/README.md b/apache-poi/README.md index ed30d9a4f3..9edf69d67c 100644 --- a/apache-poi/README.md +++ b/apache-poi/README.md @@ -8,7 +8,6 @@ This module contains articles about Apache POI. - [Merge Cells in Excel Using Apache POI](https://www.baeldung.com/java-apache-poi-merge-cells) - [Get String Value of Excel Cell with Apache POI](https://www.baeldung.com/java-apache-poi-cell-string-value) - [Read Excel Cell Value Rather Than Formula With Apache POI](https://www.baeldung.com/apache-poi-read-cell-value-formula) -- [Setting Formulas in Excel with Apache POI](https://www.baeldung.com/java-apache-poi-set-formulas) - [Insert a Row in Excel Using Apache POI](https://www.baeldung.com/apache-poi-insert-excel-row) - [Multiline Text in Excel Cell Using Apache POI](https://www.baeldung.com/apache-poi-write-multiline-text) - [Set Background Color of a Cell with Apache POI](https://www.baeldung.com/apache-poi-background-color) diff --git a/apache-poi/src/main/java/com/baeldung/poi/excel/ExcelUtility.java.orig b/apache-poi/src/main/java/com/baeldung/poi/excel/ExcelUtility.java.orig deleted file mode 100644 index c058f3abcf..0000000000 --- a/apache-poi/src/main/java/com/baeldung/poi/excel/ExcelUtility.java.orig +++ /dev/null @@ -1,128 +0,0 @@ -package com.baeldung.poi.excel; - -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; - -import org.apache.poi.ss.usermodel.Cell; -import org.apache.poi.ss.usermodel.CellType; -import org.apache.poi.ss.usermodel.DateUtil; -import org.apache.poi.ss.usermodel.Row; -import org.apache.poi.ss.usermodel.Sheet; -import org.apache.poi.ss.usermodel.Workbook; -import org.apache.poi.xssf.usermodel.XSSFWorkbook; - -public class ExcelUtility { -<<<<<<< HEAD - private static final String ENDLINE = System.getProperty("line.separator"); - - public static String readExcel(String filePath) throws IOException { - File file = new File(filePath); - FileInputStream inputStream = null; - StringBuilder toReturn = new StringBuilder(); - try { - inputStream = new FileInputStream(file); - Workbook baeuldungWorkBook = new XSSFWorkbook(inputStream); - for (Sheet sheet : baeuldungWorkBook) { - toReturn.append("--------------------------------------------------------------------") - .append(ENDLINE); - toReturn.append("Worksheet :") - .append(sheet.getSheetName()) - .append(ENDLINE); - toReturn.append("--------------------------------------------------------------------") - .append(ENDLINE); - int firstRow = sheet.getFirstRowNum(); - int lastRow = sheet.getLastRowNum(); - for (int index = firstRow + 1; index <= lastRow; index++) { - Row row = sheet.getRow(index); - toReturn.append("|| "); - for (int cellIndex = row.getFirstCellNum(); cellIndex < row.getLastCellNum(); cellIndex++) { - Cell cell = row.getCell(cellIndex, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK); - printCellValue(cell, toReturn); - } - toReturn.append(" ||") - .append(ENDLINE); - } - } - inputStream.close(); - - } catch (IOException e) { - throw e; - } - return toReturn.toString(); - } - - public static void printCellValue(Cell cell, StringBuilder toReturn) { - CellType cellType = cell.getCellType() - .equals(CellType.FORMULA) ? cell.getCachedFormulaResultType() : cell.getCellType(); - if (cellType.equals(CellType.STRING)) { - toReturn.append(cell.getStringCellValue()) - .append(" | "); - } - if (cellType.equals(CellType.NUMERIC)) { - if (DateUtil.isCellDateFormatted(cell)) { - toReturn.append(cell.getDateCellValue()) - .append(" | "); - } else { - toReturn.append(cell.getNumericCellValue()) - .append(" | "); - } - } - if (cellType.equals(CellType.BOOLEAN)) { - toReturn.append(cell.getBooleanCellValue()) - .append(" | "); - } - } -======= - private static final String ENDLINE = System.getProperty("line.separator"); - - public static String readExcel(String filePath) throws IOException { - File file = new File(filePath); - FileInputStream inputStream = null; - StringBuilder toReturn = new StringBuilder(); - try { - inputStream = new FileInputStream(file); - Workbook baeuldungWorkBook = new XSSFWorkbook(inputStream); - for (Sheet sheet : baeuldungWorkBook) { - toReturn.append("--------------------------------------------------------------------").append(ENDLINE); - toReturn.append("Worksheet :").append(sheet.getSheetName()).append(ENDLINE); - toReturn.append("--------------------------------------------------------------------").append(ENDLINE); - int firstRow = sheet.getFirstRowNum(); - int lastRow = sheet.getLastRowNum(); - for (int index = firstRow + 1; index <= lastRow; index++) { - Row row = sheet.getRow(index); - toReturn.append("|| "); - for (int cellIndex = row.getFirstCellNum(); cellIndex < row.getLastCellNum(); cellIndex++) { - Cell cell = row.getCell(cellIndex, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK); - printCellValue(cell, toReturn); - } - toReturn.append(" ||").append(ENDLINE); - } - } - inputStream.close(); - - } catch (IOException e) { - throw e; - } - return toReturn.toString(); - } - - public static void printCellValue(Cell cell, StringBuilder toReturn) { - CellType cellType = cell.getCellType().equals(CellType.FORMULA) ? cell.getCachedFormulaResultType() - : cell.getCellType(); - if (cellType.equals(CellType.STRING)) { - toReturn.append(cell.getStringCellValue()).append(" | "); - } - if (cellType.equals(CellType.NUMERIC)) { - if (DateUtil.isCellDateFormatted(cell)) { - toReturn.append(cell.getDateCellValue()).append(" | "); - } else { - toReturn.append(cell.getNumericCellValue()).append(" | "); - } - } - if (cellType.equals(CellType.BOOLEAN)) { - toReturn.append(cell.getBooleanCellValue()).append(" | "); - } - } ->>>>>>> master -} \ No newline at end of file diff --git a/apache-poi/src/test/java/com/baeldung/poi/excel/ExcelUtilityUnitTest.java.orig b/apache-poi/src/test/java/com/baeldung/poi/excel/ExcelUtilityUnitTest.java.orig deleted file mode 100644 index cfc3062b5a..0000000000 --- a/apache-poi/src/test/java/com/baeldung/poi/excel/ExcelUtilityUnitTest.java.orig +++ /dev/null @@ -1,112 +0,0 @@ -package com.baeldung.poi.excel; - -import static org.junit.Assert.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; - -import java.io.IOException; -import java.net.URISyntaxException; -import java.nio.file.Paths; -import java.text.ParseException; -import java.text.SimpleDateFormat; - -import org.junit.Before; -import org.junit.Test; - -public class ExcelUtilityUnitTest { -<<<<<<< HEAD - private static final String FILE_NAME = "baeldung.xlsx"; - private String fileLocation; - private static final String ENDLINE = System.getProperty("line.separator"); - private StringBuilder output; - - @Before - public void setupUnitTest() throws IOException, URISyntaxException, ParseException { - output = new StringBuilder(); - output.append("--------------------------------------------------------------------") - .append(ENDLINE); - output.append("Worksheet :Sheet1") - .append(ENDLINE); - output.append("--------------------------------------------------------------------") - .append(ENDLINE); - output.append("|| Name1 | Surname1 | 3.55696564113E11 | ") - .append(new SimpleDateFormat("dd/MM/yyyy").parse("4/11/2021") - .toString()) - .append(" | ‡ | ||") - .append(ENDLINE); - output.append("|| Name2 | Surname2 | 5.646513512E9 | ") - .append(new SimpleDateFormat("dd/MM/yyyy").parse("4/12/2021") - .toString()) - .append(" | false | ||") - .append(ENDLINE); - output.append("|| Name3 | Surname3 | 3.55696564113E11 | ") - .append(new SimpleDateFormat("dd/MM/yyyy").parse("4/11/2021") - .toString()) - .append(" | 7.17039641738E11 | ||") - .append(ENDLINE); - output.append("--------------------------------------------------------------------") - .append(ENDLINE); - output.append("Worksheet :Sheet2") - .append(ENDLINE); - output.append("--------------------------------------------------------------------") - .append(ENDLINE); - output.append("|| Name4 | Surname4 | 3.55675623232E11 | 13/04/2021 | ||") - .append(ENDLINE); - - fileLocation = Paths.get(ClassLoader.getSystemResource(FILE_NAME) - .toURI()) - .toString(); - } - - @Test - public void givenStringPath_whenReadExcel_thenReturnStringValue() throws IOException { - assertEquals(output.toString(), ExcelUtility.readExcel(fileLocation)); - - } - - @Test - public void givenStringPath_whenReadExcel_thenThrowException() { - assertThrows(IOException.class, () -> { - ExcelUtility.readExcel("baeldung"); - }); - } -======= - private static final String FILE_NAME = "baeldung.xlsx"; - private String fileLocation; - private static final String ENDLINE = System.getProperty("line.separator"); - private StringBuilder output; - - @Before - public void setupUnitTest() throws IOException, URISyntaxException, ParseException { - output = new StringBuilder(); - output.append("--------------------------------------------------------------------").append(ENDLINE); - output.append("Worksheet :Sheet1").append(ENDLINE); - output.append("--------------------------------------------------------------------").append(ENDLINE); - output.append("|| Name1 | Surname1 | 3.55696564113E11 | ").append(new SimpleDateFormat("dd/MM/yyyy").parse("4/11/2021").toString()).append(" | ‡ | ||") - .append(ENDLINE); - output.append("|| Name2 | Surname2 | 5.646513512E9 | ").append(new SimpleDateFormat("dd/MM/yyyy").parse("4/12/2021").toString()).append(" | false | ||") - .append(ENDLINE); - output.append("|| Name3 | Surname3 | 3.55696564113E11 | ").append(new SimpleDateFormat("dd/MM/yyyy").parse("4/11/2021").toString()).append(" | 7.17039641738E11 | ||") - .append(ENDLINE); - output.append("--------------------------------------------------------------------").append(ENDLINE); - output.append("Worksheet :Sheet2").append(ENDLINE); - output.append("--------------------------------------------------------------------").append(ENDLINE); - output.append("|| Name4 | Surname4 | 3.55675623232E11 | 13/04/2021 | ||").append(ENDLINE); - - fileLocation = Paths.get(ClassLoader.getSystemResource(FILE_NAME).toURI()).toString(); - } - - @Test - public void givenStringPath_whenReadExcel_thenReturnStringValue() throws IOException { - assertEquals(output.toString(), ExcelUtility.readExcel(fileLocation)); - - } - - @Test - public void givenStringPath_whenReadExcel_thenThrowException() { - assertThrows(IOException.class, () -> { - ExcelUtility.readExcel("baeldung"); - }); - } ->>>>>>> master - -} diff --git a/core-java-modules/core-java-8-2/README.md b/core-java-modules/core-java-8-2/README.md index 12a060ccfe..c0bc63f21f 100644 --- a/core-java-modules/core-java-8-2/README.md +++ b/core-java-modules/core-java-8-2/README.md @@ -9,4 +9,5 @@ This module contains articles about Java 8 core features - [Guide to Java BiFunction Interface](https://www.baeldung.com/java-bifunction-interface) - [Interface With Default Methods vs Abstract Class](https://www.baeldung.com/java-interface-default-method-vs-abstract-class) - [Convert Between Byte Array and UUID in Java](https://www.baeldung.com/java-byte-array-to-uuid) +- [Create a Simple “Rock-Paper-Scissors” Game in Java](https://www.baeldung.com/java-rock-paper-scissors) - [[<-- Prev]](/core-java-modules/core-java-8) diff --git a/core-java-modules/core-java-8-datetime-2/src/test/java/com/baeldung/random/RandomDatesUnitTest.java b/core-java-modules/core-java-8-datetime-2/src/test/java/com/baeldung/random/RandomDatesUnitTest.java index 6005cf93c2..68b4fd4938 100644 --- a/core-java-modules/core-java-8-datetime-2/src/test/java/com/baeldung/random/RandomDatesUnitTest.java +++ b/core-java-modules/core-java-8-datetime-2/src/test/java/com/baeldung/random/RandomDatesUnitTest.java @@ -22,6 +22,6 @@ class RandomDatesUnitTest { LocalDate end = LocalDate.now(); LocalDate random = RandomDates.between(start, end); - assertThat(random).isAfter(start).isBefore(end); + assertThat(random).isAfterOrEqualTo(start).isBefore(end); } } diff --git a/core-java-modules/core-java-concurrency-advanced-4/src/main/java/com/baeldung/lockbykey/ExampleUsage.java b/core-java-modules/core-java-concurrency-advanced-4/src/main/java/com/baeldung/lockbykey/ExampleUsage.java new file mode 100644 index 0000000000..23cfb8455a --- /dev/null +++ b/core-java-modules/core-java-concurrency-advanced-4/src/main/java/com/baeldung/lockbykey/ExampleUsage.java @@ -0,0 +1,43 @@ +package com.baeldung.lockbykey; + +/** + * This class shows examples of how you should use the lock + * + */ +public class ExampleUsage { + + void doWithSimpleExclusiveLock(String key) { + SimpleExclusiveLockByKey simpleExclusiveLockByKey = new SimpleExclusiveLockByKey(); + if (simpleExclusiveLockByKey.tryLock(key)) { + try { + // do stuff + } finally { + // it is very important to unlock in the finally block to avoid locking keys forever + simpleExclusiveLockByKey.unlock(key); + } + } + } + + // A concrete example can be found in the unit tests + void doWithLock(String key) { + LockByKey lockByKey = new LockByKey(); + lockByKey.lock(key); + try { + // do stuff + } finally { + lockByKey.unlock(key); + } + } + + // It works exactly the same as with locks + void doWithSemaphore(String key) { + SimultaneousEntriesLockByKey lockByKey = new SimultaneousEntriesLockByKey(); + lockByKey.lock(key); + try { + // do stuff + } finally { + lockByKey.unlock(key); + } + } + +} diff --git a/core-java-modules/core-java-concurrency-advanced-4/src/main/java/com/baeldung/lockbykey/LockByKey.java b/core-java-modules/core-java-concurrency-advanced-4/src/main/java/com/baeldung/lockbykey/LockByKey.java new file mode 100644 index 0000000000..f81aa6779e --- /dev/null +++ b/core-java-modules/core-java-concurrency-advanced-4/src/main/java/com/baeldung/lockbykey/LockByKey.java @@ -0,0 +1,41 @@ +package com.baeldung.lockbykey; + +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +public class LockByKey { + + private static class LockWrapper { + private final Lock lock = new ReentrantLock(); + private final AtomicInteger numberOfThreadsInQueue = new AtomicInteger(1); + + private LockWrapper addThreadInQueue() { + numberOfThreadsInQueue.incrementAndGet(); + return this; + } + + private int removeThreadFromQueue() { + return numberOfThreadsInQueue.decrementAndGet(); + } + + } + + private static ConcurrentHashMap locks = new ConcurrentHashMap(); + + public void lock(String key) { + LockWrapper lockWrapper = locks.compute(key, (k, v) -> v == null ? new LockWrapper() : v.addThreadInQueue()); + lockWrapper.lock.lock(); + } + + public void unlock(String key) { + LockWrapper lockWrapper = locks.get(key); + lockWrapper.lock.unlock(); + if (lockWrapper.removeThreadFromQueue() == 0) { + // NB : We pass in the specific value to remove to handle the case where another thread would queue right before the removal + locks.remove(key, lockWrapper); + } + } + +} diff --git a/core-java-modules/core-java-concurrency-advanced-4/src/main/java/com/baeldung/lockbykey/SimpleExclusiveLockByKey.java b/core-java-modules/core-java-concurrency-advanced-4/src/main/java/com/baeldung/lockbykey/SimpleExclusiveLockByKey.java new file mode 100644 index 0000000000..9182f9c038 --- /dev/null +++ b/core-java-modules/core-java-concurrency-advanced-4/src/main/java/com/baeldung/lockbykey/SimpleExclusiveLockByKey.java @@ -0,0 +1,18 @@ +package com.baeldung.lockbykey; + +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +public class SimpleExclusiveLockByKey { + + private static Set usedKeys= ConcurrentHashMap.newKeySet(); + + public boolean tryLock(String key) { + return usedKeys.add(key); + } + + public void unlock(String key) { + usedKeys.remove(key); + } + +} diff --git a/core-java-modules/core-java-concurrency-advanced-4/src/main/java/com/baeldung/lockbykey/SimultaneousEntriesLockByKey.java b/core-java-modules/core-java-concurrency-advanced-4/src/main/java/com/baeldung/lockbykey/SimultaneousEntriesLockByKey.java new file mode 100644 index 0000000000..9532f973fa --- /dev/null +++ b/core-java-modules/core-java-concurrency-advanced-4/src/main/java/com/baeldung/lockbykey/SimultaneousEntriesLockByKey.java @@ -0,0 +1,25 @@ +package com.baeldung.lockbykey; + +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Semaphore; + +public class SimultaneousEntriesLockByKey { + + private static final int ALLOWED_THREADS = 2; + + private static ConcurrentHashMap semaphores = new ConcurrentHashMap(); + + public void lock(String key) { + Semaphore semaphore = semaphores.compute(key, (k, v) -> v == null ? new Semaphore(ALLOWED_THREADS) : v); + semaphore.acquireUninterruptibly(); + } + + public void unlock(String key) { + Semaphore semaphore = semaphores.get(key); + semaphore.release(); + if (semaphore.availablePermits() == ALLOWED_THREADS) { + semaphores.remove(key, semaphore); + } + } + +} diff --git a/core-java-modules/core-java-concurrency-advanced-4/src/test/java/com/baeldung/lockbykey/LockByKeyUnitTest.java b/core-java-modules/core-java-concurrency-advanced-4/src/test/java/com/baeldung/lockbykey/LockByKeyUnitTest.java new file mode 100644 index 0000000000..4e43a8fb49 --- /dev/null +++ b/core-java-modules/core-java-concurrency-advanced-4/src/test/java/com/baeldung/lockbykey/LockByKeyUnitTest.java @@ -0,0 +1,106 @@ +package com.baeldung.lockbykey; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.concurrent.atomic.AtomicBoolean; + +import org.junit.jupiter.api.Test; + +public class LockByKeyUnitTest { + + @Test + void givenNoLockedKey_WhenLock_ThenSuccess() throws InterruptedException { + AtomicBoolean threadWasExecuted = new AtomicBoolean(false); + Thread thread = new Thread(() -> { + String key = "key"; + LockByKey lockByKey = new LockByKey(); + lockByKey.lock(key); + try { + threadWasExecuted.set(true); + } finally { + lockByKey.unlock(key); + } + }); + try { + thread.start(); + Thread.sleep(100); + } finally { + assertTrue(threadWasExecuted.get()); + } + } + + @Test + void givenLockedKey_WhenLock_ThenFailure() throws InterruptedException { + String key = "key"; + LockByKey lockByKey = new LockByKey(); + lockByKey.lock(key); + AtomicBoolean anotherThreadWasExecuted = new AtomicBoolean(false); + Thread threadLockingOnAnotherKey = new Thread(() -> { + LockByKey otherLockByKey = new LockByKey(); + otherLockByKey.lock(key); + try { + anotherThreadWasExecuted.set(true); + } finally { + otherLockByKey.unlock(key); + } + }); + try { + threadLockingOnAnotherKey.start(); + Thread.sleep(100); + } finally { + assertFalse(anotherThreadWasExecuted.get()); + lockByKey.unlock(key); + } + } + + @Test + void givenAnotherKeyLocked_WhenLock_ThenSuccess() throws InterruptedException { + String key = "key"; + LockByKey lockByKey = new LockByKey(); + lockByKey.lock(key); + AtomicBoolean anotherThreadWasExecuted = new AtomicBoolean(false); + Thread threadLockingOnAnotherKey = new Thread(() -> { + String anotherKey = "anotherKey"; + LockByKey otherLockByKey = new LockByKey(); + otherLockByKey.lock(anotherKey); + try { + anotherThreadWasExecuted.set(true); + } finally { + otherLockByKey.unlock(anotherKey); + } + }); + try { + threadLockingOnAnotherKey.start(); + Thread.sleep(100); + } finally { + assertTrue(anotherThreadWasExecuted.get()); + lockByKey.unlock(key); + } + } + + @Test + void givenUnlockedKey_WhenLock_ThenSuccess() throws InterruptedException { + String key = "key"; + LockByKey lockByKey = new LockByKey(); + lockByKey.lock(key); + AtomicBoolean anotherThreadWasExecuted = new AtomicBoolean(false); + Thread threadLockingOnAnotherKey = new Thread(() -> { + LockByKey otherLockByKey = new LockByKey(); + otherLockByKey.lock(key); + try { + anotherThreadWasExecuted.set(true); + } finally { + otherLockByKey.unlock(key); + } + }); + try { + lockByKey.unlock(key); + threadLockingOnAnotherKey.start(); + Thread.sleep(100); + } finally { + assertTrue(anotherThreadWasExecuted.get()); + } + } + +} diff --git a/core-java-modules/core-java-concurrency-advanced-4/src/test/java/com/baeldung/lockbykey/SimpleExclusiveLockByKeyUnitTest.java b/core-java-modules/core-java-concurrency-advanced-4/src/test/java/com/baeldung/lockbykey/SimpleExclusiveLockByKeyUnitTest.java new file mode 100644 index 0000000000..deba728664 --- /dev/null +++ b/core-java-modules/core-java-concurrency-advanced-4/src/test/java/com/baeldung/lockbykey/SimpleExclusiveLockByKeyUnitTest.java @@ -0,0 +1,51 @@ +package com.baeldung.lockbykey; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.lang.reflect.Field; +import java.util.concurrent.ConcurrentHashMap; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class SimpleExclusiveLockByKeyUnitTest { + + @BeforeEach + void cleanUpLocks() throws Exception { + Field field = SimpleExclusiveLockByKey.class.getDeclaredField("usedKeys"); + field.setAccessible(true); + field.set(null, ConcurrentHashMap.newKeySet()); + } + + @Test + void givenNoLockedKey_WhenTryLock_ThenSuccess() { + SimpleExclusiveLockByKey lockByKey = new SimpleExclusiveLockByKey(); + assertTrue(lockByKey.tryLock("key")); + } + + @Test + void givenLockedKey_WhenTryLock_ThenFailure() { + String key = "key"; + SimpleExclusiveLockByKey lockByKey = new SimpleExclusiveLockByKey(); + lockByKey.tryLock(key); + assertFalse(lockByKey.tryLock(key)); + } + + @Test + void givenAnotherKeyLocked_WhenTryLock_ThenSuccess() { + SimpleExclusiveLockByKey lockByKey = new SimpleExclusiveLockByKey(); + lockByKey.tryLock("other"); + assertTrue(lockByKey.tryLock("key")); + } + + @Test + void givenUnlockedKey_WhenTryLock_ThenSuccess() { + String key = "key"; + SimpleExclusiveLockByKey lockByKey = new SimpleExclusiveLockByKey(); + lockByKey.tryLock(key); + lockByKey.unlock(key); + assertTrue(lockByKey.tryLock(key)); + } + +} diff --git a/core-java-modules/core-java-concurrency-advanced-4/src/test/java/com/baeldung/lockbykey/SimultaneousEntriesLockByKeyUnitTest.java b/core-java-modules/core-java-concurrency-advanced-4/src/test/java/com/baeldung/lockbykey/SimultaneousEntriesLockByKeyUnitTest.java new file mode 100644 index 0000000000..ec4e7f4d80 --- /dev/null +++ b/core-java-modules/core-java-concurrency-advanced-4/src/test/java/com/baeldung/lockbykey/SimultaneousEntriesLockByKeyUnitTest.java @@ -0,0 +1,146 @@ +package com.baeldung.lockbykey; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.concurrent.atomic.AtomicBoolean; + +import org.junit.jupiter.api.Test; + +public class SimultaneousEntriesLockByKeyUnitTest { + + @Test + void givenNoKeyUsed_WhenLock_ThenSuccess() throws InterruptedException { + AtomicBoolean threadWasExecuted = new AtomicBoolean(false); + Thread thread = new Thread(() -> { + String key = "key"; + SimultaneousEntriesLockByKey lockByKey = new SimultaneousEntriesLockByKey(); + lockByKey.lock(key); + try { + threadWasExecuted.set(true); + } finally { + lockByKey.unlock(key); + } + }); + try { + thread.start(); + Thread.sleep(100); + } finally { + assertTrue(threadWasExecuted.get()); + } + } + + @Test + void givenKeyLockedWithRemainingPermits_WhenLock_ThenSuccess() throws InterruptedException { + String key = "key"; + SimultaneousEntriesLockByKey lockByKey = new SimultaneousEntriesLockByKey(); + lockByKey.lock(key); + AtomicBoolean anotherThreadWasExecuted = new AtomicBoolean(false); + Thread threadLockingOnAnotherKey = new Thread(() -> { + SimultaneousEntriesLockByKey otherLockByKeyWithSemaphore = new SimultaneousEntriesLockByKey(); + otherLockByKeyWithSemaphore.lock(key); + try { + anotherThreadWasExecuted.set(true); + } finally { + otherLockByKeyWithSemaphore.unlock(key); + } + }); + try { + threadLockingOnAnotherKey.start(); + Thread.sleep(100); + } finally { + assertTrue(anotherThreadWasExecuted.get()); + lockByKey.unlock(key); + } + } + + @Test + void givenKeyLockedWithNoRemainingPermits_WhenLock_ThenFailure() throws InterruptedException { + String key = "key"; + SimultaneousEntriesLockByKey lockByKey = new SimultaneousEntriesLockByKey(); + lockByKey.lock(key); + AtomicBoolean anotherThreadWasExecuted = new AtomicBoolean(false); + Thread threadLockingOnAnotherKey1 = new Thread(() -> { + SimultaneousEntriesLockByKey otherLockByKeyWithSemaphore = new SimultaneousEntriesLockByKey(); + otherLockByKeyWithSemaphore.lock(key); + try { + Thread.sleep(200); // make sure this thread will release the lock after the assertion + } catch (InterruptedException e) { + + } finally { + otherLockByKeyWithSemaphore.unlock(key); + } + }); + Thread threadLockingOnAnotherKey2 = new Thread(() -> { + SimultaneousEntriesLockByKey otherLockByKey = new SimultaneousEntriesLockByKey(); + try { + Thread.sleep(50); // make sure thread1 will acquire the key first + } catch (InterruptedException e) { + } + otherLockByKey.lock(key); + try { + anotherThreadWasExecuted.set(true); + } finally { + otherLockByKey.unlock(key); + } + }); + try { + threadLockingOnAnotherKey1.start(); + threadLockingOnAnotherKey2.start(); + Thread.sleep(100); + } finally { + assertFalse(anotherThreadWasExecuted.get()); + lockByKey.unlock(key); + } + } + + @Test + void givenAnotherKeyLocked_WhenLock_ThenSuccess() throws InterruptedException { + String key = "key"; + SimultaneousEntriesLockByKey lockByKey = new SimultaneousEntriesLockByKey(); + lockByKey.lock(key); + AtomicBoolean anotherThreadWasExecuted = new AtomicBoolean(false); + Thread threadLockingOnAnotherKey = new Thread(() -> { + String anotherKey = "anotherKey"; + SimultaneousEntriesLockByKey otherLockByKey = new SimultaneousEntriesLockByKey(); + otherLockByKey.lock(anotherKey); + try { + anotherThreadWasExecuted.set(true); + } finally { + otherLockByKey.unlock(anotherKey); + } + }); + try { + threadLockingOnAnotherKey.start(); + Thread.sleep(100); + } finally { + assertTrue(anotherThreadWasExecuted.get()); + lockByKey.unlock(key); + } + } + + @Test + void givenUnlockedKey_WhenLock_ThenSuccess() throws InterruptedException { + String key = "key"; + SimultaneousEntriesLockByKey lockByKey = new SimultaneousEntriesLockByKey(); + lockByKey.lock(key); + AtomicBoolean anotherThreadWasExecuted = new AtomicBoolean(false); + Thread threadLockingOnAnotherKey = new Thread(() -> { + SimultaneousEntriesLockByKey otherLockByKey = new SimultaneousEntriesLockByKey(); + otherLockByKey.lock(key); + try { + anotherThreadWasExecuted.set(true); + } finally { + otherLockByKey.unlock(key); + } + }); + try { + lockByKey.unlock(key); + threadLockingOnAnotherKey.start(); + Thread.sleep(100); + } finally { + assertTrue(anotherThreadWasExecuted.get()); + } + } + +} diff --git a/core-java-modules/core-java-exceptions-3/src/test/java/com/baeldung/exceptions/illegalmonitorstate/IllegalMonitorStateExceptionUnitTest.java b/core-java-modules/core-java-exceptions-3/src/test/java/com/baeldung/exceptions/illegalmonitorstate/IllegalMonitorStateExceptionManualTest.java similarity index 91% rename from core-java-modules/core-java-exceptions-3/src/test/java/com/baeldung/exceptions/illegalmonitorstate/IllegalMonitorStateExceptionUnitTest.java rename to core-java-modules/core-java-exceptions-3/src/test/java/com/baeldung/exceptions/illegalmonitorstate/IllegalMonitorStateExceptionManualTest.java index 857ab02c13..31807255e8 100644 --- a/core-java-modules/core-java-exceptions-3/src/test/java/com/baeldung/exceptions/illegalmonitorstate/IllegalMonitorStateExceptionUnitTest.java +++ b/core-java-modules/core-java-exceptions-3/src/test/java/com/baeldung/exceptions/illegalmonitorstate/IllegalMonitorStateExceptionManualTest.java @@ -7,7 +7,12 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import org.junit.jupiter.api.Test; -public class IllegalMonitorStateExceptionUnitTest { +/** + * Needs to be run manually in order to demonstrate the IllegalMonitorStateException scenarios. + * + * There are some intermittent test failures in Jenkins that require further investigation. + */ +public class IllegalMonitorStateExceptionManualTest { @Test void whenSyncSenderAndSyncReceiverAreUsed_thenIllegalMonitorExceptionShouldNotBeThrown() throws InterruptedException { diff --git a/core-java-modules/core-java-io-4/README.md b/core-java-modules/core-java-io-4/README.md index be58338fd8..39b820b3ba 100644 --- a/core-java-modules/core-java-io-4/README.md +++ b/core-java-modules/core-java-io-4/README.md @@ -7,4 +7,5 @@ This module contains articles about core Java input and output (IO) - [Java File Separator vs File Path Separator](https://www.baeldung.com/java-file-vs-file-path-separator) - [Simulate touch Command in Java](https://www.baeldung.com/java-simulate-touch-command) - [SequenceInputStream Class in Java](https://www.baeldung.com/java-sequenceinputstream) +- [Read a File Into a Map in Java](https://www.baeldung.com/java-read-file-into-map) - [[<-- Prev]](/core-java-modules/core-java-io-3) diff --git a/core-java-modules/core-java-networking-2/src/main/java/com/baeldung/mail/EmailService.java b/core-java-modules/core-java-networking-2/src/main/java/com/baeldung/mail/EmailService.java index 3d1e25e7a4..3e40cf53f7 100644 --- a/core-java-modules/core-java-networking-2/src/main/java/com/baeldung/mail/EmailService.java +++ b/core-java-modules/core-java-networking-2/src/main/java/com/baeldung/mail/EmailService.java @@ -67,12 +67,17 @@ public class EmailService { MimeBodyPart mimeBodyPart = new MimeBodyPart(); mimeBodyPart.setContent(msg, "text/html; charset=utf-8"); + String msgStyled = "This is my bold-red email using JavaMailer"; + MimeBodyPart mimeBodyPartWithStyledText = new MimeBodyPart(); + mimeBodyPartWithStyledText.setContent(msgStyled, "text/html; charset=utf-8"); + MimeBodyPart attachmentBodyPart = new MimeBodyPart(); attachmentBodyPart.attachFile(getFile()); Multipart multipart = new MimeMultipart(); multipart.addBodyPart(mimeBodyPart); + multipart.addBodyPart(mimeBodyPartWithStyledText); multipart.addBodyPart(attachmentBodyPart); message.setContent(multipart); diff --git a/core-java-modules/core-java-networking-2/src/test/java/com/baeldung/mail/EmailServiceLiveTest.java b/core-java-modules/core-java-networking-2/src/test/java/com/baeldung/mail/EmailServiceLiveTest.java index 7f543bc612..cec4cfcb55 100644 --- a/core-java-modules/core-java-networking-2/src/test/java/com/baeldung/mail/EmailServiceLiveTest.java +++ b/core-java-modules/core-java-networking-2/src/test/java/com/baeldung/mail/EmailServiceLiveTest.java @@ -36,6 +36,7 @@ public class EmailServiceLiveTest { MimeMessage receivedMessage = receivedMessages[0]; assertEquals("Mail Subject", subjectFromMessage(receivedMessage)); assertEquals("This is my first email using JavaMailer", emailTextFrom(receivedMessage)); + assertEquals("This is my bold-red email using JavaMailer", emailStyledTextFrom(receivedMessage)); assertEquals("sample attachment content", attachmentContentsFrom(receivedMessage)); } @@ -50,9 +51,16 @@ public class EmailServiceLiveTest { .toString(); } + private static String emailStyledTextFrom(MimeMessage receivedMessage) throws IOException, MessagingException { + return ((MimeMultipart) receivedMessage.getContent()) + .getBodyPart(1) + .getContent() + .toString(); + } + private static String attachmentContentsFrom(MimeMessage receivedMessage) throws Exception { return ((MimeMultipart) receivedMessage.getContent()) - .getBodyPart(1) + .getBodyPart(2) .getContent() .toString(); } diff --git a/core-java-modules/core-java-nio-2/README.md b/core-java-modules/core-java-nio-2/README.md index 9152a494d8..c405cb7c77 100644 --- a/core-java-modules/core-java-nio-2/README.md +++ b/core-java-modules/core-java-nio-2/README.md @@ -12,4 +12,5 @@ This module contains articles about core Java non-blocking input and output (IO) - [Java NIO DatagramChannel](https://www.baeldung.com/java-nio-datagramchannel) - [Java – Path vs File](https://www.baeldung.com/java-path-vs-file) - [What Is the Difference Between NIO and NIO.2?](https://www.baeldung.com/java-nio-vs-nio-2) +- [Guide to ByteBuffer](https://www.baeldung.com/java-bytebuffer) - [[<-- Prev]](/core-java-modules/core-java-nio) diff --git a/graphql/graphql-java/README.md b/graphql/graphql-java/README.md index e3fd818400..f37506a9fd 100644 --- a/graphql/graphql-java/README.md +++ b/graphql/graphql-java/README.md @@ -5,3 +5,4 @@ This module contains articles about GraphQL with Java ## Relevant articles: - [Introduction to GraphQL](https://www.baeldung.com/graphql) +- [Make a Call to a GraphQL Service from a Java Application](https://www.baeldung.com/java-call-graphql-service) diff --git a/httpclient-2/README.md b/httpclient-2/README.md index 7c2d5862bd..4f9805063c 100644 --- a/httpclient-2/README.md +++ b/httpclient-2/README.md @@ -11,5 +11,5 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring - [How to Set TLS Version in Apache HttpClient](https://www.baeldung.com/apache-httpclient-tls) - [Reading an HTTP Response Body as a String in Java](https://www.baeldung.com/java-http-response-body-as-string) - [How To Get Cookies From the Apache HttpClient Response](https://www.baeldung.com/java-apache-httpclient-cookies) -- [Enabling Logging for Apache HttpClient](https://www.baeldung.com/java-httpclient-enable-logging) +- [Enabling Logging for Apache HttpClient](https://www.baeldung.com/apache-httpclient-enable-logging) - More articles: [[<-- prev]](../httpclient) diff --git a/httpclient-simple/README.md b/httpclient-simple/README.md index 93fb22ac1e..8875af1ea0 100644 --- a/httpclient-simple/README.md +++ b/httpclient-simple/README.md @@ -11,7 +11,7 @@ This module contains articles about HTTPClient that are part of the HTTPClient E - [Custom HTTP Header with the HttpClient](https://www.baeldung.com/httpclient-custom-http-header) - [HttpClient Basic Authentication](https://www.baeldung.com/httpclient-4-basic-authentication) - [Posting with HttpClient](https://www.baeldung.com/httpclient-post-http-request) -- [Adding Parameters to HttpClient Requests](https://www.baeldung.com/java-httpclient-parameters) +- [Adding Parameters to HttpClient Requests](https://www.baeldung.com/apache-httpclient-parameters) ### Running the Tests diff --git a/jakarta-ee/pom.xml b/jakarta-ee/pom.xml new file mode 100644 index 0000000000..074ca1eec8 --- /dev/null +++ b/jakarta-ee/pom.xml @@ -0,0 +1,111 @@ + + 4.0.0 + + com.baeldung + mvc-2.0 + 1.0-SNAPSHOT + war + + mvc-2.0 + + + 9.0.0 + 2.0.0 + 2.0.0 + 5.8.2 + C:/glassfish6 + admin + mvn-domain + 1.10.19 + + ${local.glassfish.home}\\domains\\${local.glassfish.domain}\\config\\domain-passwords + + + + + + jakarta.platform + jakarta.jakartaee-web-api + ${jakartaee-api.version} + provided + + + + jakarta.mvc + jakarta.mvc-api + ${jakarta.mvc-api.version} + + + + org.eclipse.krazo + krazo-jersey + ${krazo.version} + + + org.junit.jupiter + junit-jupiter-api + ${junit.jupiter.version} + test + + + org.mockito + mockito-all + ${mockito.version} + test + + + + + + mvc-2.0 + + + org.glassfish.maven.plugin + maven-glassfish-plugin + 2.1 + + ${local.glassfish.home} + admin + + password + + + ${local.glassfish.domain} + 8080 + 4848 + + + + + ${project.artifactId} + target/${project.build.finalName}.war + + + + true + false + true + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.0 + + 1.8 + 1.8 + + + + org.apache.maven.plugins + maven-war-plugin + + false + + + + + diff --git a/jakarta-ee/src/main/java/com/baeldung/eclipse/krazo/User.java b/jakarta-ee/src/main/java/com/baeldung/eclipse/krazo/User.java new file mode 100644 index 0000000000..a2253b6aa6 --- /dev/null +++ b/jakarta-ee/src/main/java/com/baeldung/eclipse/krazo/User.java @@ -0,0 +1,84 @@ +package com.baeldung.eclipse.krazo; + +import jakarta.enterprise.context.RequestScoped; +import jakarta.inject.Named; +import jakarta.mvc.RedirectScoped; +import jakarta.mvc.binding.MvcBinding; +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Null; +import jakarta.validation.constraints.Size; +import jakarta.ws.rs.FormParam; + +import java.io.Serializable; + +@Named("user") +@RedirectScoped +public class User implements Serializable { + @MvcBinding + @Null + private String id; + + @MvcBinding + @NotNull + @Size(min = 1, message = "Name cannot be blank") + @FormParam("name") + private String name; + + @MvcBinding + @Min(value = 18, message = "The minimum age of the user should be 18 years") + @FormParam("age") + private int age; + + @MvcBinding + @Email(message = "The email cannot be blank and should be in a valid format") + @Size(min=3, message = "Email cannot be empty") + @FormParam("email") + private String email; + + @MvcBinding + @Null + @FormParam("phone") + private String phone; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getPhone() { + return phone; + } + + public void setPhone(String phone) { + this.phone = phone; + } +} diff --git a/jakarta-ee/src/main/java/com/baeldung/eclipse/krazo/UserApplication.java b/jakarta-ee/src/main/java/com/baeldung/eclipse/krazo/UserApplication.java new file mode 100644 index 0000000000..5a272806cb --- /dev/null +++ b/jakarta-ee/src/main/java/com/baeldung/eclipse/krazo/UserApplication.java @@ -0,0 +1,11 @@ +package com.baeldung.eclipse.krazo; + +import jakarta.ws.rs.ApplicationPath; +import jakarta.ws.rs.core.Application; + +/** + * Default JAX-RS application listening on /app + */ +@ApplicationPath("/app") +public class UserApplication extends Application { +} diff --git a/jakarta-ee/src/main/java/com/baeldung/eclipse/krazo/UserController.java b/jakarta-ee/src/main/java/com/baeldung/eclipse/krazo/UserController.java new file mode 100644 index 0000000000..92ddf73571 --- /dev/null +++ b/jakarta-ee/src/main/java/com/baeldung/eclipse/krazo/UserController.java @@ -0,0 +1,85 @@ +package com.baeldung.eclipse.krazo; + +import jakarta.inject.Inject; +import jakarta.mvc.Controller; +import jakarta.mvc.Models; +import jakarta.mvc.binding.BindingResult; +import jakarta.mvc.security.CsrfProtected; +import jakarta.validation.Valid; +import jakarta.ws.rs.BeanParam; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.MediaType; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +/** + * The class contains two controllers and a REST API + */ +@Path("users") +public class UserController { + @Inject + private BindingResult bindingResult; + + private static final List users = new ArrayList<>(); + + @Inject + private Models models; + + /** + * This is a controller. It displays a initial form to the user. + * @return The view name + */ + @GET + @Controller + public String showForm() { + return "user.jsp"; + } + + /** + * The method handles the form submits + * Handles HTTP POST and is CSRF protected. The client invoking this controller should provide a CSRF token. + * @param user The user details that has to be stored + * @return Returns a view name + */ + @POST + @Controller + @CsrfProtected + public String saveUser(@Valid @BeanParam User user) { + if (bindingResult.isFailed()) { + models.put("errors", bindingResult.getAllErrors()); + return "user.jsp"; + } + String id = UUID.randomUUID().toString(); + user.setId(id); + users.add(user); + return "redirect:users/success"; + } + + /** + * Handles a redirect view + * @return The view name + */ + @GET + @Controller + @Path("success") + public String saveUserSuccess() { + return "success.jsp"; + } + + /** + * The REST API that returns all the user details in the JSON format + * @return The list of users that are saved. The List is converted into Json Array. + * If no user is present a empty array is returned + */ + @GET + @Produces(MediaType.APPLICATION_JSON) + public List getUsers() { + return users; + } + +} diff --git a/jakarta-ee/src/main/webapp/WEB-INF/beans.xml b/jakarta-ee/src/main/webapp/WEB-INF/beans.xml new file mode 100644 index 0000000000..d068fbd3e4 --- /dev/null +++ b/jakarta-ee/src/main/webapp/WEB-INF/beans.xml @@ -0,0 +1,6 @@ + + + diff --git a/jakarta-ee/src/main/webapp/WEB-INF/views/success.jsp b/jakarta-ee/src/main/webapp/WEB-INF/views/success.jsp new file mode 100644 index 0000000000..19d45e46ba --- /dev/null +++ b/jakarta-ee/src/main/webapp/WEB-INF/views/success.jsp @@ -0,0 +1,47 @@ +<%@ page contentType="text/html;charset=UTF-8" language="java" %> +<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> + + + + MVC 2.0 + + + + + + + + + + +
+
+
+
+ +
+

User created successfully!

+
+
+ +
+ +
+
+ + + + + + \ No newline at end of file diff --git a/jakarta-ee/src/main/webapp/WEB-INF/views/user.jsp b/jakarta-ee/src/main/webapp/WEB-INF/views/user.jsp new file mode 100644 index 0000000000..a36655950d --- /dev/null +++ b/jakarta-ee/src/main/webapp/WEB-INF/views/user.jsp @@ -0,0 +1,89 @@ +<%@ page contentType="text/html;charset=UTF-8" language="java" %> +<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> + + + + MVC 2.0 + + + + + + + + + + +
+
+
+

+ User Details +

+
+ + + +
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+
+
+ +
+
+ + +
+ +
+ +
+
+ + + + + + \ No newline at end of file diff --git a/jakarta-ee/src/main/webapp/styles.css b/jakarta-ee/src/main/webapp/styles.css new file mode 100644 index 0000000000..9cc9e62f12 --- /dev/null +++ b/jakarta-ee/src/main/webapp/styles.css @@ -0,0 +1,28 @@ +body, html { + font-family: Raleway, serif; + font-weight: 300; +} + +.bg-dark { + background-color: #63b175 !important; + font-weight: 600 !important; +} + +body { + padding-top: 80px; +} + +@media (max-width: 979px) { + body { + padding-top: 0; + } +} + +label { + font-weight: bold; +} + +.hr-dark { + border-top: 2px solid #000; + margin-bottom: 20px; +} \ No newline at end of file diff --git a/jakarta-ee/src/test/java/com/baeldung/eclipse/krazo/AppTest.java b/jakarta-ee/src/test/java/com/baeldung/eclipse/krazo/AppTest.java new file mode 100644 index 0000000000..6934d1fca2 --- /dev/null +++ b/jakarta-ee/src/test/java/com/baeldung/eclipse/krazo/AppTest.java @@ -0,0 +1,16 @@ +package com.baeldung.eclipse.krazo; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * Dummy Test + */ +public class AppTest { + + @Test + public void test() { + assertTrue(true); + } +} diff --git a/jakarta-ee/src/test/java/com/baeldung/eclipse/krazo/UserControllerUnitTest.java b/jakarta-ee/src/test/java/com/baeldung/eclipse/krazo/UserControllerUnitTest.java new file mode 100644 index 0000000000..5e79924ed7 --- /dev/null +++ b/jakarta-ee/src/test/java/com/baeldung/eclipse/krazo/UserControllerUnitTest.java @@ -0,0 +1,116 @@ +package com.baeldung.eclipse.krazo; + +import com.baeldung.eclipse.krazo.User; +import com.baeldung.eclipse.krazo.UserController; +import jakarta.mvc.Models; +import jakarta.mvc.binding.BindingResult; +import org.eclipse.krazo.core.ModelsImpl; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.when; + +/** + * The class contains unit tests. We do only unit tests. Most of the classes are mocked + */ +@DisplayName("Eclipse Krazo MVC 2.0 Test Suite") +class UserControllerUnitTest { + + @InjectMocks + UserController userController = new UserController(); + + @Mock + Models models; + + @Mock + BindingResult bindingResult; + + @BeforeEach + public void setUpClass() { + MockitoAnnotations.initMocks(this); + } + + @Test + @DisplayName("Test Show Form") + void whenShowForm_thenReturnViewName() { + assertNotNull(userController.showForm()); + assertEquals("user.jsp", userController.showForm()); + } + + @Test + @DisplayName("Test Save User Success") + void whenSaveUser_thenReturnSuccess() { + when(bindingResult.isFailed()).thenReturn(false); + + User user = new User(); + + assertNotNull(userController.saveUser(user)); + assertDoesNotThrow(() -> userController.saveUser(user)); + assertEquals("redirect:users/success", userController.saveUser(user)); + } + + @Test + @DisplayName("Test Save User Binding Errors") + void whenSaveUser_thenReturnError() { + when(bindingResult.isFailed()).thenReturn(true); + Models testModels = new ModelsImpl(); + when(models.put(anyString(), any())).thenReturn(testModels); + User user = getUser(); + assertNotNull(userController.saveUser(user)); + assertDoesNotThrow(() -> userController.saveUser(user)); + assertEquals("user.jsp", userController.saveUser(user)); + } + + @Test + @DisplayName("Test Save User Success View") + void whenSaveUserSuccess_thenRedirectSuccess() { + assertNotNull(userController.saveUserSuccess()); + assertDoesNotThrow(() -> userController.saveUserSuccess()); + assertEquals("success.jsp", userController.saveUserSuccess()); + } + + @Test + @DisplayName("Test Get Users API") + void whenGetUser_thenReturnUsers() { + when(bindingResult.isFailed()).thenReturn(false); + + User user= getUser(); + + assertNotNull(user); + assertEquals(30, user.getAge()); + assertEquals("john doe", user.getName()); + assertEquals("anymail", user.getEmail()); + assertEquals("99887766554433", user.getPhone()); + assertEquals("1", user.getId()); + + userController.saveUser(user); + userController.saveUser(user); + userController.saveUser(user); + + assertNotNull(userController.getUsers()); + assertDoesNotThrow(() -> userController.getUsers()); + assertEquals(3, userController.getUsers().size()); + + } + + private User getUser() { + User user = new User(); + user.setId("1"); + user.setName("john doe"); + user.setAge(30); + user.setEmail("anymail"); + user.setPhone("99887766554433"); + return user; + } + +} diff --git a/java-numbers-4/pom.xml b/java-numbers-4/pom.xml index 9b2e799840..40fe17cc0d 100644 --- a/java-numbers-4/pom.xml +++ b/java-numbers-4/pom.xml @@ -25,6 +25,11 @@ ${commons-lang3.version} test + + com.google.guava + guava + ${guava.version} + diff --git a/java-numbers-4/src/main/java/com/baeldung/convertLongToInt/ConvertLongToInt.java b/java-numbers-4/src/main/java/com/baeldung/convertLongToInt/ConvertLongToInt.java new file mode 100644 index 0000000000..0638505c2d --- /dev/null +++ b/java-numbers-4/src/main/java/com/baeldung/convertLongToInt/ConvertLongToInt.java @@ -0,0 +1,44 @@ +package com.baeldung.convertLongToInt; + +import java.math.BigDecimal; +import java.util.Optional; +import java.util.function.Function; + +import com.google.common.primitives.Ints; + +public class ConvertLongToInt { + + static Function convert = val -> Optional.ofNullable(val) + .map(Long::intValue) + .orElse(null); + + public static int longToIntCast(long number) { + return (int) number; + } + + public static int longToIntJavaWithMath(long number) { + return Math.toIntExact(number); + } + + public static int longToIntJavaWithLambda(long number) { + return convert.apply(number); + } + + public static int longToIntBoxingValues(long number) { + return Long.valueOf(number) + .intValue(); + } + + public static int longToIntGuava(long number) { + return Ints.checkedCast(number); + } + + public static int longToIntGuavaSaturated(long number) { + return Ints.saturatedCast(number); + } + + public static int longToIntWithBigDecimal(long number) { + return new BigDecimal(number).intValueExact(); + } + +} diff --git a/java-numbers-4/src/test/java/com/baeldung/convertLongToInt/ConvertLongToIntUnitTest.java b/java-numbers-4/src/test/java/com/baeldung/convertLongToInt/ConvertLongToIntUnitTest.java new file mode 100644 index 0000000000..38fa37b664 --- /dev/null +++ b/java-numbers-4/src/test/java/com/baeldung/convertLongToInt/ConvertLongToIntUnitTest.java @@ -0,0 +1,23 @@ +package com.baeldung.convertLongToInt; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; + +class ConvertLongToIntUnitTest { + + @Test + void longToInt() { + long number = 186762L; + int expected = 186762; + + assertEquals(expected, ConvertLongToInt.longToIntCast(number)); + assertEquals(expected, ConvertLongToInt.longToIntJavaWithMath(number)); + assertEquals(expected, ConvertLongToInt.longToIntJavaWithLambda(number)); + assertEquals(expected, ConvertLongToInt.longToIntBoxingValues(number)); + assertEquals(expected, ConvertLongToInt.longToIntGuava(number)); + assertEquals(expected, ConvertLongToInt.longToIntGuavaSaturated(number)); + assertEquals(expected, ConvertLongToInt.longToIntWithBigDecimal(number)); + } + +} \ No newline at end of file diff --git a/javax-servlets/src/main/webapp/sample.txt b/javax-servlets/src/main/webapp/WEB-INF/sample.txt similarity index 100% rename from javax-servlets/src/main/webapp/sample.txt rename to javax-servlets/src/main/webapp/WEB-INF/sample.txt diff --git a/libraries-testing/README.md b/libraries-testing/README.md index 5498c73094..880c3dd2e6 100644 --- a/libraries-testing/README.md +++ b/libraries-testing/README.md @@ -8,7 +8,7 @@ This module contains articles about test libraries. - [Introduction to JSONassert](https://www.baeldung.com/jsonassert) - [Serenity BDD and Screenplay](https://www.baeldung.com/serenity-screenplay) - [Serenity BDD with Spring and JBehave](https://www.baeldung.com/serenity-spring-jbehave) -- [Introduction to Awaitility](https://www.baeldung.com/awaitlity-testing) +- [Introduction to Awaitility](https://www.baeldung.com/awaitility-testing) - [Introduction to Hoverfly in Java](https://www.baeldung.com/hoverfly) - [Testing with Hamcrest](https://www.baeldung.com/java-junit-hamcrest-guide) - [Introduction To DBUnit](https://www.baeldung.com/java-dbunit) diff --git a/lombok-2/README.md b/lombok-2/README.md index 25d097a7ea..650dc5ddab 100644 --- a/lombok-2/README.md +++ b/lombok-2/README.md @@ -7,4 +7,5 @@ This module contains articles about Project Lombok. - [Using Lombok’s @Accessors Annotation](https://www.baeldung.com/lombok-accessors) - [Declaring Val and Var Variables in Lombok](https://www.baeldung.com/java-lombok-val-var) - [Lombok Using @With Annotations](https://www.baeldung.com/lombok-with-annotations) +- [Lombok's @ToString Annotation](https://www.baeldung.com/lombok-tostring) - More articles: [[<-- prev]](../lombok) diff --git a/lombok-2/src/main/java/com/baeldung/lombok/tostring/Account.java b/lombok-2/src/main/java/com/baeldung/lombok/tostring/Account.java new file mode 100644 index 0000000000..641ad1e1a3 --- /dev/null +++ b/lombok-2/src/main/java/com/baeldung/lombok/tostring/Account.java @@ -0,0 +1,56 @@ +package com.baeldung.lombok.tostring; + +import lombok.ToString; + +@ToString +public class Account { + + private String name; + + // render this field before any others (the highest ranked) + @ToString.Include(rank = 1) + private String id; + + @ToString.Exclude + private String accountNumber; + + // automatically excluded + private String $ignored; + + @ToString.Include + String description() { + return "Account description"; + } + + public String getAccountNumber() { + return accountNumber; + } + + public void setAccountNumber(String accountNumber) { + this.accountNumber = accountNumber; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String get$ignored() { + return $ignored; + } + + public void set$ignored(String value) { + this.$ignored = value; + } +} diff --git a/lombok-2/src/main/java/com/baeldung/lombok/tostring/AccountType.java b/lombok-2/src/main/java/com/baeldung/lombok/tostring/AccountType.java new file mode 100644 index 0000000000..7f99b5ca35 --- /dev/null +++ b/lombok-2/src/main/java/com/baeldung/lombok/tostring/AccountType.java @@ -0,0 +1,9 @@ +package com.baeldung.lombok.tostring; + +import lombok.ToString; + +@ToString +public enum AccountType { + CHECKING, + SAVING +} diff --git a/lombok-2/src/main/java/com/baeldung/lombok/tostring/RewardAccount.java b/lombok-2/src/main/java/com/baeldung/lombok/tostring/RewardAccount.java new file mode 100644 index 0000000000..9ac9c6afa6 --- /dev/null +++ b/lombok-2/src/main/java/com/baeldung/lombok/tostring/RewardAccount.java @@ -0,0 +1,27 @@ +package com.baeldung.lombok.tostring; + +import lombok.ToString; + +@ToString +public class RewardAccount extends Account { + + private String rewardAccountId; + + private Object[] relatedAccounts; + + public String getRewardAccountId() { + return rewardAccountId; + } + + public void setRewardAccountId(String rewardAccountId) { + this.rewardAccountId = rewardAccountId; + } + + public Object[] getRelatedAccounts() { + return relatedAccounts; + } + + public void setRelatedAccounts(Object[] relatedAccounts) { + this.relatedAccounts = relatedAccounts; + } +} diff --git a/lombok-2/src/main/java/com/baeldung/lombok/tostring/SavingAccount.java b/lombok-2/src/main/java/com/baeldung/lombok/tostring/SavingAccount.java new file mode 100644 index 0000000000..dfba31cf27 --- /dev/null +++ b/lombok-2/src/main/java/com/baeldung/lombok/tostring/SavingAccount.java @@ -0,0 +1,17 @@ +package com.baeldung.lombok.tostring; + +import lombok.ToString; + +@ToString(callSuper = true) +public class SavingAccount extends Account { + + private String savingAccountId; + + public String getSavingAccountId() { + return savingAccountId; + } + + public void setSavingAccountId(String savingAccountId) { + this.savingAccountId = savingAccountId; + } +} diff --git a/lombok-2/src/test/java/com/baeldung/lombok/tostring/ToStringUnitTest.java b/lombok-2/src/test/java/com/baeldung/lombok/tostring/ToStringUnitTest.java new file mode 100644 index 0000000000..cb56ad912d --- /dev/null +++ b/lombok-2/src/test/java/com/baeldung/lombok/tostring/ToStringUnitTest.java @@ -0,0 +1,66 @@ +package com.baeldung.lombok.tostring; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +class ToStringUnitTest { + + @Test + void whenPrintObject_thenOutputIsCorrect() { + Account account = new Account(); + account.setId("12345"); + account.setName("An account"); + account.setAccountNumber("11111"); // should not be present in output + account.set$ignored("ignored value"); // should not be present in output + + assertThat(account.toString()) + .isEqualTo("Account(id=12345, name=An account, description=Account description)"); + } + + @Test + void whenPrintSubclassWithSuper_thenOutputIsCorrect() { + SavingAccount savingAccount = new SavingAccount(); + savingAccount.setSavingAccountId("5678"); + savingAccount.setId("12345"); + savingAccount.setName("An account"); + + assertThat(savingAccount.toString()) + .isEqualTo("SavingAccount(super=Account(id=12345, name=An account, description=Account description), savingAccountId=5678)"); + } + +@Test +void whenPrintArrays_thenOutputIsCorrect() { + RewardAccount account = new RewardAccount(); + account.setRewardAccountId("12345"); + + // circular ref, just for demonstration + Object[] relatedAccounts = new Object[2]; + relatedAccounts[0] = "54321"; + relatedAccounts[1] = relatedAccounts; + + account.setRelatedAccounts(relatedAccounts); + + assertThat(account.toString()) + .isEqualTo("RewardAccount(rewardAccountId=12345, relatedAccounts=[54321, [...]])"); +} + + @Test + void whenPrintSubclassWithoutSuper_thenOutputIsCorrect() { + RewardAccount rewardAccount = new RewardAccount(); + rewardAccount.setRewardAccountId("12345"); + + assertThat(rewardAccount.toString()) + .isEqualTo("RewardAccount(rewardAccountId=12345, relatedAccounts=null)"); + } + + @Test + void whenPrintEnum_thenOutputIsCorrect() { + assertThat(AccountType.CHECKING.toString()) + .isEqualTo("AccountType.CHECKING"); + + assertThat(AccountType.SAVING.toString()) + .isEqualTo("AccountType.SAVING"); + } + +} diff --git a/maven-modules/maven-simple/maven-profiles/pom.xml b/maven-modules/maven-simple/maven-profiles/pom.xml index 322dada104..ba915038ad 100644 --- a/maven-modules/maven-simple/maven-profiles/pom.xml +++ b/maven-modules/maven-simple/maven-profiles/pom.xml @@ -5,7 +5,7 @@ 4.0.0 com.baeldung maven-profiles - 0.0.1-SNAPSHOT + 1.0.0-SNAPSHOT maven-profiles diff --git a/maven-modules/maven-simple/parent-project/core/pom.xml b/maven-modules/maven-simple/parent-project/core/pom.xml index ec25c9ace5..8f7371639f 100644 --- a/maven-modules/maven-simple/parent-project/core/pom.xml +++ b/maven-modules/maven-simple/parent-project/core/pom.xml @@ -10,7 +10,7 @@ parent-project com.baeldung - 1.0-SNAPSHOT + 1.0.0-SNAPSHOT diff --git a/maven-modules/maven-simple/parent-project/pom.xml b/maven-modules/maven-simple/parent-project/pom.xml index a68f8e63bc..fce9aa3f72 100644 --- a/maven-modules/maven-simple/parent-project/pom.xml +++ b/maven-modules/maven-simple/parent-project/pom.xml @@ -4,14 +4,13 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 parent-project - 1.0-SNAPSHOT parent-project pom com.baeldung maven-simple - 0.0.1-SNAPSHOT + 1.0.0-SNAPSHOT diff --git a/maven-modules/maven-simple/parent-project/service/pom.xml b/maven-modules/maven-simple/parent-project/service/pom.xml index 1953ec8638..39945af248 100644 --- a/maven-modules/maven-simple/parent-project/service/pom.xml +++ b/maven-modules/maven-simple/parent-project/service/pom.xml @@ -10,7 +10,7 @@ parent-project com.baeldung - 1.0-SNAPSHOT + 1.0.0-SNAPSHOT diff --git a/maven-modules/maven-simple/parent-project/webapp/pom.xml b/maven-modules/maven-simple/parent-project/webapp/pom.xml index bd13c5aeb8..1ab1321b20 100644 --- a/maven-modules/maven-simple/parent-project/webapp/pom.xml +++ b/maven-modules/maven-simple/parent-project/webapp/pom.xml @@ -10,7 +10,7 @@ parent-project com.baeldung - 1.0-SNAPSHOT + 1.0.0-SNAPSHOT diff --git a/maven-modules/maven-simple/plugin-management/pom.xml b/maven-modules/maven-simple/plugin-management/pom.xml index 2fb2d5ed41..3c4bd886ac 100644 --- a/maven-modules/maven-simple/plugin-management/pom.xml +++ b/maven-modules/maven-simple/plugin-management/pom.xml @@ -9,7 +9,7 @@ maven-simple com.baeldung - 0.0.1-SNAPSHOT + 1.0.0-SNAPSHOT @@ -56,8 +56,8 @@ - 3.8.1 - 3.2.0 + 3.10.0 + 3.3.0 \ No newline at end of file diff --git a/maven-modules/maven-simple/plugin-management/submodule-1/pom.xml b/maven-modules/maven-simple/plugin-management/submodule-1/pom.xml index c36e092254..ff08dec9a6 100644 --- a/maven-modules/maven-simple/plugin-management/submodule-1/pom.xml +++ b/maven-modules/maven-simple/plugin-management/submodule-1/pom.xml @@ -8,7 +8,7 @@ plugin-management com.baeldung - 0.0.1-SNAPSHOT + 1.0.0-SNAPSHOT diff --git a/maven-modules/maven-simple/plugin-management/submodule-2/pom.xml b/maven-modules/maven-simple/plugin-management/submodule-2/pom.xml index e50d3cc26d..5db76cebdb 100644 --- a/maven-modules/maven-simple/plugin-management/submodule-2/pom.xml +++ b/maven-modules/maven-simple/plugin-management/submodule-2/pom.xml @@ -8,7 +8,7 @@ plugin-management com.baeldung - 0.0.1-SNAPSHOT + 1.0.0-SNAPSHOT \ No newline at end of file diff --git a/maven-modules/maven-simple/pom.xml b/maven-modules/maven-simple/pom.xml index 938e2240f8..fe59259758 100644 --- a/maven-modules/maven-simple/pom.xml +++ b/maven-modules/maven-simple/pom.xml @@ -5,6 +5,7 @@ 4.0.0 maven-simple maven-simple + 1.0.0-SNAPSHOT pom diff --git a/muleesb/pom.xml b/muleesb/pom.xml index f6cfa7d5d1..d78cebada2 100644 --- a/muleesb/pom.xml +++ b/muleesb/pom.xml @@ -108,7 +108,7 @@ org.mule.tools.maven mule-maven-plugin - 2.2.1 + ${mule-maven-plugin.version} standalone ${mule.version} @@ -203,7 +203,7 @@ mulesoft-release mulesoft release repository default - https://repository.mulesoft.org/releases/ + https://repository.mulesoft.org/nexus/content/repositories/public/ false @@ -212,9 +212,10 @@ 3.9.0 - 1.2 + 1.8 1.3.6 - 1.7 + 1.10 + 2.2.1 diff --git a/nginx-forward-proxy/forward b/nginx-forward-proxy/forward new file mode 100644 index 0000000000..4e8ca8b29f --- /dev/null +++ b/nginx-forward-proxy/forward @@ -0,0 +1,7 @@ +server { + listen 8888; + location / { + resolver 8.8.8.8; + proxy_pass http://$http_host$uri$is_args$args; + } +} \ No newline at end of file diff --git a/nginx-forward-proxy/package-lock.json b/nginx-forward-proxy/package-lock.json new file mode 100644 index 0000000000..b70787ec67 --- /dev/null +++ b/nginx-forward-proxy/package-lock.json @@ -0,0 +1,339 @@ +{ + "name": "nginx-forward-proxy", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "asn1": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", + "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" + }, + "aws4": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", + "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==" + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "requires": { + "tweetnacl": "^0.14.3" + } + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "requires": { + "assert-plus": "^1.0.0" + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "requires": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" + }, + "form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "requires": { + "assert-plus": "^1.0.0" + } + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" + }, + "har-validator": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "requires": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + } + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" + }, + "json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==" + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" + }, + "jsprim": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", + "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.4.0", + "verror": "1.10.0" + } + }, + "mime-db": { + "version": "1.51.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", + "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==" + }, + "mime-types": { + "version": "2.1.34", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz", + "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==", + "requires": { + "mime-db": "1.51.0" + } + }, + "oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" + }, + "psl": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", + "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==" + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + }, + "qs": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", + "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==" + }, + "request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "sshpk": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", + "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + } + }, + "tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "requires": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + } + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "requires": { + "punycode": "^2.1.0" + } + }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + } + } +} diff --git a/nginx-forward-proxy/package.json b/nginx-forward-proxy/package.json new file mode 100644 index 0000000000..4691542900 --- /dev/null +++ b/nginx-forward-proxy/package.json @@ -0,0 +1,14 @@ +{ + "name": "nginx-forward-proxy", + "version": "1.0.0", + "description": "Simple Client for Connecting to a Forward Proxy", + "main": "proxytest.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "Olsi Seferi", + "license": "ISC", + "dependencies": { + "request": "^2.88.2" + } +} diff --git a/nginx-forward-proxy/proxytest.js b/nginx-forward-proxy/proxytest.js new file mode 100644 index 0000000000..dc55ef6620 --- /dev/null +++ b/nginx-forward-proxy/proxytest.js @@ -0,0 +1,11 @@ +var request = require('request'); + +request({ + 'url':'http://www.google.com/', + 'method': "GET", + 'proxy':'http://192.168.100.40:8888' +},function (error, response, body) { + if (!error && response.statusCode == 200) { + console.log(body); + } +}) diff --git a/persistence-modules/fauna/.gitignore b/persistence-modules/fauna/.gitignore new file mode 100644 index 0000000000..c37fa0c4b3 --- /dev/null +++ b/persistence-modules/fauna/.gitignore @@ -0,0 +1 @@ +/application.properties diff --git a/persistence-modules/fauna/pom.xml b/persistence-modules/fauna/pom.xml new file mode 100644 index 0000000000..67aabb7501 --- /dev/null +++ b/persistence-modules/fauna/pom.xml @@ -0,0 +1,56 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.6.2 + + + com.baeldung + fauna-blog + 0.0.1-SNAPSHOT + fauna-blog + Blogging Service built with FaunaDB + + 17 + + + + org.springframework.boot + spring-boot-starter-security + + + org.springframework.boot + spring-boot-starter-web + + + com.faunadb + faunadb-java + 4.2.0 + compile + + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.security + spring-security-test + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/spring-5-autowiring-beans/src/main/java/com/baeldung/autowiring/App.java b/persistence-modules/fauna/src/main/java/com/baeldung/faunablog/FaunaBlogApplication.java similarity index 55% rename from spring-5-autowiring-beans/src/main/java/com/baeldung/autowiring/App.java rename to persistence-modules/fauna/src/main/java/com/baeldung/faunablog/FaunaBlogApplication.java index d2d0db7a60..12739342bf 100644 --- a/spring-5-autowiring-beans/src/main/java/com/baeldung/autowiring/App.java +++ b/persistence-modules/fauna/src/main/java/com/baeldung/faunablog/FaunaBlogApplication.java @@ -1,14 +1,13 @@ -package com.baeldung.autowiring; +package com.baeldung.faunablog; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.context.annotation.ComponentScan; @SpringBootApplication -public class App { +public class FaunaBlogApplication { public static void main(String[] args) { - SpringApplication.run(App.class, args); + SpringApplication.run(FaunaBlogApplication.class, args); } } diff --git a/persistence-modules/fauna/src/main/java/com/baeldung/faunablog/FaunaConfiguration.java b/persistence-modules/fauna/src/main/java/com/baeldung/faunablog/FaunaConfiguration.java new file mode 100644 index 0000000000..9964431475 --- /dev/null +++ b/persistence-modules/fauna/src/main/java/com/baeldung/faunablog/FaunaConfiguration.java @@ -0,0 +1,25 @@ +package com.baeldung.faunablog; + +import com.faunadb.client.FaunaClient; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.net.MalformedURLException; + +@Configuration +class FaunaConfiguration { + @Value("https://db.${fauna.region}.fauna.com/") + private String faunaUrl; + + @Value("${fauna.secret}") + private String faunaSecret; + + @Bean + FaunaClient getFaunaClient() throws MalformedURLException { + return FaunaClient.builder() + .withEndpoint(faunaUrl) + .withSecret(faunaSecret) + .build(); + } +} diff --git a/persistence-modules/fauna/src/main/java/com/baeldung/faunablog/WebSecurityConfiguration.java b/persistence-modules/fauna/src/main/java/com/baeldung/faunablog/WebSecurityConfiguration.java new file mode 100644 index 0000000000..da99b7578e --- /dev/null +++ b/persistence-modules/fauna/src/main/java/com/baeldung/faunablog/WebSecurityConfiguration.java @@ -0,0 +1,35 @@ +package com.baeldung.faunablog; + +import com.baeldung.faunablog.users.FaunaUserDetailsService; +import com.faunadb.client.FaunaClient; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.core.userdetails.UserDetailsService; + +@Configuration +@EnableWebSecurity +@EnableGlobalMethodSecurity(prePostEnabled = true) +public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter { + + @Autowired + private FaunaClient faunaClient; + + @Override + protected void configure(HttpSecurity http) throws Exception { + http.csrf().disable(); + http.authorizeRequests() + .antMatchers("/**").permitAll() + .and().httpBasic(); + } + + @Bean + @Override + public UserDetailsService userDetailsService() { + return new FaunaUserDetailsService(faunaClient); + } +} diff --git a/persistence-modules/fauna/src/main/java/com/baeldung/faunablog/posts/Author.java b/persistence-modules/fauna/src/main/java/com/baeldung/faunablog/posts/Author.java new file mode 100644 index 0000000000..ec4854621d --- /dev/null +++ b/persistence-modules/fauna/src/main/java/com/baeldung/faunablog/posts/Author.java @@ -0,0 +1,3 @@ +package com.baeldung.faunablog.posts; + +public record Author(String username, String name) {} diff --git a/persistence-modules/fauna/src/main/java/com/baeldung/faunablog/posts/Post.java b/persistence-modules/fauna/src/main/java/com/baeldung/faunablog/posts/Post.java new file mode 100644 index 0000000000..62b6558a37 --- /dev/null +++ b/persistence-modules/fauna/src/main/java/com/baeldung/faunablog/posts/Post.java @@ -0,0 +1,5 @@ +package com.baeldung.faunablog.posts; + +import java.time.Instant; + +public record Post(String id, String title, String content, Author author, Instant created, Long version) {} diff --git a/persistence-modules/fauna/src/main/java/com/baeldung/faunablog/posts/PostsController.java b/persistence-modules/fauna/src/main/java/com/baeldung/faunablog/posts/PostsController.java new file mode 100644 index 0000000000..e8e6316ea8 --- /dev/null +++ b/persistence-modules/fauna/src/main/java/com/baeldung/faunablog/posts/PostsController.java @@ -0,0 +1,50 @@ +package com.baeldung.faunablog.posts; + +import com.faunadb.client.errors.NotFoundException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.server.ResponseStatusException; + +import java.util.List; +import java.util.concurrent.ExecutionException; + +@RestController +@RequestMapping("/posts") +public class PostsController { + @Autowired + private PostsService postsService; + + @GetMapping + public List listPosts(@RequestParam(value = "author", required = false) String author) throws ExecutionException, InterruptedException { + return author == null ? postsService.getAllPosts() : postsService.getAuthorPosts("graham"); + } + + @GetMapping("/{id}") + public Post getPost(@PathVariable("id") String id, @RequestParam(value = "before", required = false) Long before) + throws ExecutionException, InterruptedException { + return postsService.getPost(id, before); + } + + @PostMapping + @ResponseStatus(HttpStatus.NO_CONTENT) + @PreAuthorize("isAuthenticated()") + public void createPost(@RequestBody UpdatedPost post) throws ExecutionException, InterruptedException { + String name = SecurityContextHolder.getContext().getAuthentication().getName(); + postsService.createPost(name, post.title(), post.content()); + } + + @PutMapping("/{id}") + @ResponseStatus(HttpStatus.NO_CONTENT) + @PreAuthorize("isAuthenticated()") + public void updatePost(@PathVariable("id") String id, @RequestBody UpdatedPost post) + throws ExecutionException, InterruptedException { + postsService.updatePost(id, post.title(), post.content()); + } + + @ExceptionHandler(NotFoundException.class) + @ResponseStatus(HttpStatus.NOT_FOUND) + public void postNotFound() {} +} diff --git a/persistence-modules/fauna/src/main/java/com/baeldung/faunablog/posts/PostsService.java b/persistence-modules/fauna/src/main/java/com/baeldung/faunablog/posts/PostsService.java new file mode 100644 index 0000000000..5143a24b28 --- /dev/null +++ b/persistence-modules/fauna/src/main/java/com/baeldung/faunablog/posts/PostsService.java @@ -0,0 +1,124 @@ +package com.baeldung.faunablog.posts; + +import com.faunadb.client.FaunaClient; +import com.faunadb.client.types.Value; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.time.Instant; +import java.util.Collection; +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.stream.Collectors; + +import static com.faunadb.client.query.Language.*; + +@Component +public class PostsService { + @Autowired + private FaunaClient faunaClient; + + Post getPost(String id, Long before) throws ExecutionException, InterruptedException { + var query = Get(Ref(Collection("posts"), id)); + if (before != null) { + query = At(Value(before - 1), query); + } + + var postResult= faunaClient.query( + Let( + "post", query + ).in( + Obj( + "post", Var("post"), + "author", Get(Select(Arr(Value("data"), Value("authorRef")), Var("post"))) + ) + )).get(); + + return parsePost(postResult); + } + + List getAllPosts() throws ExecutionException, InterruptedException { + var postsResult = faunaClient.query(Map( + Paginate( + Join( + Documents(Collection("posts")), + Index("posts_sort_by_created_desc") + ) + ), + Lambda( + Arr(Value("extra"), Value("ref")), + Obj( + "post", Get(Var("ref")), + "author", Get(Select(Arr(Value("data"), Value("authorRef")), Get(Var("ref")))) + ) + ) + )).get(); + + var posts = postsResult.at("data").asCollectionOf(Value.class).get(); + return posts.stream().map(this::parsePost).collect(Collectors.toList()); + } + + List getAuthorPosts(String author) throws ExecutionException, InterruptedException { + var postsResult = faunaClient.query(Map( + Paginate( + Join( + Match(Index("posts_by_author"), Select(Value("ref"), Get(Match(Index("users_by_username"), Value(author))))), + Index("posts_sort_by_created_desc") + ) + ), + Lambda( + Arr(Value("extra"), Value("ref")), + Obj( + "post", Get(Var("ref")), + "author", Get(Select(Arr(Value("data"), Value("authorRef")), Get(Var("ref")))) + ) + ) + )).get(); + + var posts = postsResult.at("data").asCollectionOf(Value.class).get(); + return posts.stream().map(this::parsePost).collect(Collectors.toList()); + } + + public void createPost(String author, String title, String contents) throws ExecutionException, InterruptedException { + faunaClient.query( + Create(Collection("posts"), + Obj( + "data", Obj( + "title", Value(title), + "contents", Value(contents), + "created", Now(), + "authorRef", Select(Value("ref"), Get(Match(Index("users_by_username"), Value(author))))) + ) + ) + ).get(); + } + + public void updatePost(String id, String title, String contents) throws ExecutionException, InterruptedException { + faunaClient.query( + Update(Ref(Collection("posts"), id), + Obj( + "data", Obj( + "title", Value(title), + "contents", Value(contents)) + ) + ) + ).get(); + } + + private Post parsePost(Value entry) { + var author = entry.at("author"); + var post = entry.at("post"); + + return new Post( + post.at("ref").to(Value.RefV.class).get().getId(), + post.at("data", "title").to(String.class).get(), + post.at("data", "contents").to(String.class).get(), + new Author( + author.at("data", "username").to(String.class).get(), + author.at("data", "name").to(String.class).get() + ), + post.at("data", "created").to(Instant.class).get(), + post.at("ts").to(Long.class).get() + ); + } +} diff --git a/persistence-modules/fauna/src/main/java/com/baeldung/faunablog/posts/UpdatedPost.java b/persistence-modules/fauna/src/main/java/com/baeldung/faunablog/posts/UpdatedPost.java new file mode 100644 index 0000000000..9850cd5927 --- /dev/null +++ b/persistence-modules/fauna/src/main/java/com/baeldung/faunablog/posts/UpdatedPost.java @@ -0,0 +1,3 @@ +package com.baeldung.faunablog.posts; + +public record UpdatedPost(String title, String content) {} diff --git a/persistence-modules/fauna/src/main/java/com/baeldung/faunablog/users/FaunaUserDetailsService.java b/persistence-modules/fauna/src/main/java/com/baeldung/faunablog/users/FaunaUserDetailsService.java new file mode 100644 index 0000000000..2e88aaa477 --- /dev/null +++ b/persistence-modules/fauna/src/main/java/com/baeldung/faunablog/users/FaunaUserDetailsService.java @@ -0,0 +1,44 @@ +package com.baeldung.faunablog.users; + +import com.faunadb.client.FaunaClient; +import com.faunadb.client.types.Value; +import org.springframework.security.core.userdetails.User; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.UsernameNotFoundException; + +import java.util.concurrent.ExecutionException; + +import static com.faunadb.client.query.Language.*; + +public class FaunaUserDetailsService implements UserDetailsService { + private FaunaClient faunaClient; + + public FaunaUserDetailsService(FaunaClient faunaClient) { + this.faunaClient = faunaClient; + } + + @Override + public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { + try { + Value user = faunaClient.query(Map( + Paginate(Match(Index("users_by_username"), Value(username))), + Lambda(Value("user"), Get(Var("user"))))) + .get(); + + Value userData = user.at("data").at(0).orNull(); + if (userData == null) { + throw new UsernameNotFoundException("User not found"); + } + + return User.withDefaultPasswordEncoder() + .username(userData.at("data", "username").to(String.class).orNull()) + .password(userData.at("data", "password").to(String.class).orNull()) + .roles("USER") + .build(); + } catch (ExecutionException | InterruptedException e) { + throw new RuntimeException(e); + } + } +} + diff --git a/persistence-modules/fauna/src/main/resources/application.properties b/persistence-modules/fauna/src/main/resources/application.properties new file mode 100644 index 0000000000..e69de29bb2 diff --git a/persistence-modules/hibernate-mapping-2/src/test/java/com/baeldung/hibernate/manytomany/HibernateManyToManyAnnotationMainIntegrationTest.java b/persistence-modules/hibernate-mapping-2/src/test/java/com/baeldung/hibernate/manytomany/HibernateManyToManyAnnotationMainIntegrationTest.java index 71051c821c..5255cb040f 100644 --- a/persistence-modules/hibernate-mapping-2/src/test/java/com/baeldung/hibernate/manytomany/HibernateManyToManyAnnotationMainIntegrationTest.java +++ b/persistence-modules/hibernate-mapping-2/src/test/java/com/baeldung/hibernate/manytomany/HibernateManyToManyAnnotationMainIntegrationTest.java @@ -52,9 +52,11 @@ public class HibernateManyToManyAnnotationMainIntegrationTest { for(Employee employee : employeeList) { assertNotNull(employee.getProjects()); + assertEquals(2, employee.getProjects().size()); } for(Project project : projectList) { assertNotNull(project.getEmployees()); + assertEquals(2, project.getEmployees().size()); } } @@ -70,6 +72,11 @@ public class HibernateManyToManyAnnotationMainIntegrationTest { for (String emp : employeeData) { Employee employee = new Employee(emp.split(" ")[0], emp.split(" ")[1]); employee.setProjects(projects); + + for (Project proj : projects) { + proj.getEmployees().add(employee); + } + session.persist(employee); } } diff --git a/persistence-modules/java-cassandra/pom.xml b/persistence-modules/java-cassandra/pom.xml index 6df75edc56..b0b98b040a 100644 --- a/persistence-modules/java-cassandra/pom.xml +++ b/persistence-modules/java-cassandra/pom.xml @@ -50,6 +50,25 @@ + + + integration-lite-first + + + + + org.apache.maven.plugins + maven-surefire-plugin + + 1 + true + + + + + + + 3.1.2 diff --git a/persistence-modules/java-mongodb/README.md b/persistence-modules/java-mongodb/README.md index fe30c2999e..2b7fcd3de0 100644 --- a/persistence-modules/java-mongodb/README.md +++ b/persistence-modules/java-mongodb/README.md @@ -13,3 +13,4 @@ This module contains articles about MongoDB in Java. - [BSON to JSON Document Conversion in Java](https://www.baeldung.com/java-convert-bson-to-json) - [How to Check Field Existence in MongoDB?](https://www.baeldung.com/mongodb-check-field-exists) - [Get Last Inserted Document ID in MongoDB With Java Driver](https://www.baeldung.com/java-mongodb-last-inserted-id) +- [Update Multiple Fields in a MongoDB Document](https://www.baeldung.com/mongodb-update-multiple-fields) diff --git a/persistence-modules/java-mongodb/src/main/java/com/baeldung/mongo/CollectionExistence.java b/persistence-modules/java-mongodb/src/main/java/com/baeldung/mongo/CollectionExistence.java new file mode 100644 index 0000000000..074913af4e --- /dev/null +++ b/persistence-modules/java-mongodb/src/main/java/com/baeldung/mongo/CollectionExistence.java @@ -0,0 +1,100 @@ +package com.baeldung.mongo; + +import java.util.ArrayList; + +import org.bson.Document; + +import com.mongodb.DB; +import com.mongodb.MongoClient; +import com.mongodb.client.MongoCollection; +import com.mongodb.client.MongoDatabase; + +public class CollectionExistence { + + private static MongoClient mongoClient; + + private static String testCollectionName; + private static String databaseName; + + public static void setUp() { + if (mongoClient == null) { + mongoClient = new MongoClient("localhost", 27017); + } + databaseName = "baeldung"; + testCollectionName = "student"; + } + + public static void collectionExistsSolution() { + + DB db = mongoClient.getDB(databaseName); + + System.out.println("collectionName " + testCollectionName + db.collectionExists(testCollectionName)); + + } + + public static void createCollectionSolution() { + + MongoDatabase database = mongoClient.getDatabase(databaseName); + + try { + database.createCollection(testCollectionName); + + } catch (Exception exception) { + System.err.println("Collection already Exists"); + } + + } + + public static void listCollectionNamesSolution() { + + MongoDatabase database = mongoClient.getDatabase(databaseName); + boolean collectionExists = database.listCollectionNames() + .into(new ArrayList()) + .contains(testCollectionName); + + System.out.println("collectionExists:- " + collectionExists); + + } + + public static void countSolution() { + + MongoDatabase database = mongoClient.getDatabase(databaseName); + + MongoCollection collection = database.getCollection(testCollectionName); + + System.out.println(collection.count()); + + } + + public static void main(String args[]) { + + // + // Connect to cluster (default is localhost:27017) + // + setUp(); + + // + // Check the db existence using DB class's method + // + collectionExistsSolution(); + + // + // Check the db existence using the createCollection method of MongoDatabase class + // + createCollectionSolution(); + + // + // Check the db existence using the listCollectionNames method of MongoDatabase class + // + listCollectionNamesSolution(); + + // + // Check the db existence using the count method of MongoDatabase class + // + countSolution(); + + } + +} + + diff --git a/persistence-modules/java-mongodb/src/main/java/com/baeldung/mongo/PushOperations.java b/persistence-modules/java-mongodb/src/main/java/com/baeldung/mongo/PushOperations.java new file mode 100644 index 0000000000..fa1f9ddc96 --- /dev/null +++ b/persistence-modules/java-mongodb/src/main/java/com/baeldung/mongo/PushOperations.java @@ -0,0 +1,99 @@ +package com.baeldung.mongo; + +import java.io.FileNotFoundException; +import java.io.IOException; + +import org.bson.Document; + +import com.mongodb.BasicDBObject; +import com.mongodb.DBObject; +import com.mongodb.MongoClient; +import com.mongodb.client.MongoCollection; +import com.mongodb.client.MongoDatabase; +import com.mongodb.client.model.Filters; +import com.mongodb.client.model.Updates; +import com.mongodb.client.result.UpdateResult; + +public class PushOperations { + + private static MongoClient mongoClient; + private static String testCollectionName; + private static String databaseName; + + public static void setUp() { + if (mongoClient == null) { + mongoClient = new MongoClient("localhost", 27017); + } + + databaseName = "baeldung"; + testCollectionName = "orders"; + + } + + public static void pushOperationUsingDBObject() { + + MongoDatabase database = mongoClient.getDatabase(databaseName); + MongoCollection collection = database.getCollection(testCollectionName); + DBObject listItem = new BasicDBObject("items", new BasicDBObject("itemName", "PIZZA MANIA").append("quantity", 1) + .append("price", 800)); + BasicDBObject searchFilter = new BasicDBObject("customerId", 1023); + BasicDBObject updateQuery = new BasicDBObject(); + updateQuery.append("$push", listItem); + UpdateResult updateResult = collection.updateOne(searchFilter, updateQuery); + + System.out.println("updateResult:- " + updateResult); + } + + public static void pushOperationUsingDocument() { + + MongoDatabase database = mongoClient.getDatabase(databaseName); + MongoCollection collection = database.getCollection(testCollectionName); + + Document item = new Document().append("itemName", "PIZZA MANIA") + .append("quantity", 1) + .append("price", 800); + UpdateResult updateResult = collection.updateOne(Filters.eq("customerId", 1023), Updates.push("items", item)); + + System.out.println("updateResult:- " + updateResult); + } + + public static void addToSetOperation() { + + MongoDatabase database = mongoClient.getDatabase(databaseName); + MongoCollection collection = database.getCollection(testCollectionName); + + Document item = new Document().append("itemName", "PIZZA MANIA") + .append("quantity", 1) + .append("price", 800); + UpdateResult updateResult = collection.updateOne(Filters.eq("customerId", 1023), Updates.addToSet("items", item)); + System.out.println("updateResult:- " + updateResult); + } + + public static void main(String args[]) { + + // + // Connect to cluster (default is localhost:27017) + // + setUp(); + + // + // Push document into the array using DBObject + // + + pushOperationUsingDBObject(); + + // + // Push document into the array using Document. + // + + pushOperationUsingDocument(); + + // + // Push document into the array using addToSet operator. + // + addToSetOperation(); + + } + +} + diff --git a/persistence-modules/java-mongodb/src/main/java/com/baeldung/mongo/update/MultipleFieldsExample.java b/persistence-modules/java-mongodb/src/main/java/com/baeldung/mongo/update/MultipleFieldsExample.java index b2fcddeafb..ebc56cbfd0 100644 --- a/persistence-modules/java-mongodb/src/main/java/com/baeldung/mongo/update/MultipleFieldsExample.java +++ b/persistence-modules/java-mongodb/src/main/java/com/baeldung/mongo/update/MultipleFieldsExample.java @@ -10,35 +10,35 @@ import com.mongodb.client.result.UpdateResult; public class MultipleFieldsExample { - public static void main(String[] args) { + public static void main(String[] args) { - // - // Connect to cluster (default is localhost:27017) - // + // + // Connect to cluster (default is localhost:27017) + // - MongoClient mongoClient = new MongoClient("localhost", 27017); - MongoDatabase database = mongoClient.getDatabase("baeldung"); - MongoCollection collection = database.getCollection("employee"); + MongoClient mongoClient = new MongoClient("localhost", 27017); + MongoDatabase database = mongoClient.getDatabase("baeldung"); + MongoCollection collection = database.getCollection("employee"); - // - // Filter on the basis of employee_id - // + // + // Filter on the basis of employee_id + // - BasicDBObject searchQuery = new BasicDBObject("employee_id", 794875); + BasicDBObject searchQuery = new BasicDBObject("employee_id", 794875); - // - // Update the fields in Document - // + // + // Update the fields in Document + // - BasicDBObject updateFields = new BasicDBObject(); - updateFields.append("department_id", 3); - updateFields.append("job", "Sales Manager"); - BasicDBObject setQuery = new BasicDBObject(); - setQuery.append("$set", updateFields); - UpdateResult updateResult = collection.updateMany(searchQuery, setQuery); + BasicDBObject updateFields = new BasicDBObject(); + updateFields.append("department_id", 3); + updateFields.append("job", "Sales Manager"); + BasicDBObject setQuery = new BasicDBObject(); + setQuery.append("$set", updateFields); + UpdateResult updateResult = collection.updateMany(searchQuery, setQuery); - System.out.println("updateResult:- " + updateResult); - System.out.println("updateResult:- " + updateResult.getModifiedCount()); + System.out.println("updateResult:- " + updateResult); + System.out.println("updateResult:- " + updateResult.getModifiedCount()); - } + } } diff --git a/persistence-modules/java-mongodb/src/main/java/com/baeldung/mongo/update/UpdateFields.java b/persistence-modules/java-mongodb/src/main/java/com/baeldung/mongo/update/UpdateFields.java new file mode 100644 index 0000000000..a1b051e74c --- /dev/null +++ b/persistence-modules/java-mongodb/src/main/java/com/baeldung/mongo/update/UpdateFields.java @@ -0,0 +1,128 @@ +package com.baeldung.mongo.update; + +import org.bson.Document; + +import com.mongodb.MongoClient; +import com.mongodb.client.MongoCollection; +import com.mongodb.client.MongoDatabase; +import com.mongodb.client.model.Filters; +import com.mongodb.client.model.FindOneAndReplaceOptions; +import com.mongodb.client.model.FindOneAndUpdateOptions; +import com.mongodb.client.model.ReturnDocument; +import com.mongodb.client.model.Updates; +import com.mongodb.client.result.UpdateResult; + +public class UpdateFields { + + private static MongoClient mongoClient; + private static MongoDatabase database; + private static MongoCollection collection; + + public static void updateOne() { + + UpdateResult updateResult = collection.updateOne(Filters.eq("student_name", "Paul Starc"), Updates.set("address", "Hostel 2")); + + System.out.println("updateResult:- " + updateResult); + } + + public static void updateMany() { + + UpdateResult updateResult = collection.updateMany(Filters.lt("age", 20), Updates.set("Review", true)); + + System.out.println("updateResult:- " + updateResult); + + } + + public static void replaceOne() { + + Document replaceDocument = new Document(); + replaceDocument.append("student_id", 8764) + .append("student_name", "Paul Starc") + .append("address", "Hostel 3") + .append("age", 18) + .append("roll_no", 199406); + + UpdateResult updateResult = collection.replaceOne(Filters.eq("student_id", 8764), replaceDocument); + + System.out.println("updateResult:- " + updateResult); + + } + + public static void findOneAndReplace() { + + Document replaceDocument = new Document(); + replaceDocument.append("student_id", 8764) + .append("student_name", "Paul Starc") + .append("address", "Hostel 4") + .append("age", 18) + .append("roll_no", 199406); + Document sort = new Document("roll_no", 1); + Document projection = new Document("_id", 0).append("student_id", 1) + .append("address", 1); + Document resultDocument = collection.findOneAndReplace(Filters.eq("student_id", 8764), replaceDocument, new FindOneAndReplaceOptions().upsert(true) + .sort(sort) + .projection(projection) + .returnDocument(ReturnDocument.AFTER)); + + System.out.println("resultDocument:- " + resultDocument); + + } + + public static void findOneAndUpdate() { + + Document sort = new Document("roll_no", 1); + Document projection = new Document("_id", 0).append("student_id", 1) + .append("address", 1); + Document resultDocument = collection.findOneAndUpdate(Filters.eq("student_id", 8764), Updates.inc("roll_no", 5), new FindOneAndUpdateOptions().upsert(true) + .sort(sort) + .projection(projection) + .returnDocument(ReturnDocument.AFTER)); + + System.out.println("resultDocument:- " + resultDocument); + } + + public static void setup() { + if (mongoClient == null) { + mongoClient = new MongoClient("localhost", 27017); + database = mongoClient.getDatabase("baeldung"); + collection = database.getCollection("student"); + + } + } + + public static void main(String[] args) { + + // + // Connect to cluster (default is localhost:27017) + // + setup(); + + // + // Update a document using updateOne method + // + updateOne(); + + // + // Update documents using updateMany method + // + updateMany(); + + // + // replace a document using replaceOne method + // + replaceOne(); + + // + // replace a document using findOneAndReplace method + // + findOneAndReplace(); + + // + // Update a document using findOneAndUpdate method + // + findOneAndUpdate(); + + } + +} + diff --git a/persistence-modules/java-mongodb/src/main/java/com/baeldung/mongo/update/UpdateMultipleFields.java b/persistence-modules/java-mongodb/src/main/java/com/baeldung/mongo/update/UpdateMultipleFields.java index 20af6d99cb..96dd086ed7 100644 --- a/persistence-modules/java-mongodb/src/main/java/com/baeldung/mongo/update/UpdateMultipleFields.java +++ b/persistence-modules/java-mongodb/src/main/java/com/baeldung/mongo/update/UpdateMultipleFields.java @@ -11,26 +11,25 @@ import com.mongodb.client.result.UpdateResult; public class UpdateMultipleFields { - public static void main(String[] args) { + public static void main(String[] args) { - // - // Connect to cluster - // + // + // Connect to cluster + // - MongoClient mongoClient = new MongoClient("localhost", 27007); - MongoDatabase database = mongoClient.getDatabase("baeldung"); - MongoCollection collection = database.getCollection("employee"); + MongoClient mongoClient = new MongoClient("localhost", 27007); + MongoDatabase database = mongoClient.getDatabase("baeldung"); + MongoCollection collection = database.getCollection("employee"); - // - // Update query - // + // + // Update query + // - UpdateResult updateResult = collection.updateMany(Filters.eq("employee_id", 794875), - Updates.combine(Updates.set("department_id", 4), Updates.set("job", "Sales Manager"))); + UpdateResult updateResult = collection.updateMany(Filters.eq("employee_id", 794875), Updates.combine(Updates.set("department_id", 4), Updates.set("job", "Sales Manager"))); - System.out.println("updateResult:- " + updateResult); - System.out.println("updateResult:- " + updateResult.getModifiedCount()); + System.out.println("updateResult:- " + updateResult); + System.out.println("updateResult:- " + updateResult.getModifiedCount()); - } + } -} \ No newline at end of file +} diff --git a/persistence-modules/java-mongodb/src/test/java/com/baeldung/mongo/CollectionExistenceLiveTest.java b/persistence-modules/java-mongodb/src/test/java/com/baeldung/mongo/CollectionExistenceLiveTest.java new file mode 100644 index 0000000000..ad839d1219 --- /dev/null +++ b/persistence-modules/java-mongodb/src/test/java/com/baeldung/mongo/CollectionExistenceLiveTest.java @@ -0,0 +1,98 @@ +package com.baeldung.mongo; + +import static org.junit.Assert.assertEquals; + +import java.util.ArrayList; + +import org.bson.Document; +import org.junit.Before; +import org.junit.Test; + +import com.mongodb.DB; +import com.mongodb.MongoClient; +import com.mongodb.client.MongoCollection; +import com.mongodb.client.MongoDatabase; + +public class CollectionExistenceLiveTest { + + private MongoClient mongoClient; + private String testCollectionName; + private String databaseName; + + @Before + public void setup() { + if (mongoClient == null) { + mongoClient = new MongoClient("localhost", 27017); + databaseName = "baeldung"; + testCollectionName = "student"; + + // Create a new collection if it doesn't exists. + try { + MongoDatabase database = mongoClient.getDatabase(databaseName); + database.createCollection(testCollectionName); + + } catch (Exception exception) { + + System.out.println("Collection already Exists"); + } + + } + } + + @Test + public void givenCreateCollection_whenCollectionAlreadyExists_thenCheckingForCollectionExistence() { + + MongoDatabase database = mongoClient.getDatabase(databaseName); + Boolean collectionStatus = false; + Boolean expectedStatus = true; + + try { + database.createCollection(testCollectionName); + + } catch (Exception exception) { + collectionStatus = true; + System.err.println("Collection already Exists"); + } + + assertEquals(expectedStatus, collectionStatus); + + } + + @Test + public void givenCollectionExists_whenCollectionAlreadyExists_thenCheckingForCollectionExistence() { + + DB db = mongoClient.getDB(databaseName); + Boolean collectionStatus = db.collectionExists(testCollectionName); + + Boolean expectedStatus = true; + assertEquals(expectedStatus, collectionStatus); + + } + + @Test + public void givenListCollectionNames_whenCollectionAlreadyExists_thenCheckingForCollectionExistence() { + + MongoDatabase database = mongoClient.getDatabase(databaseName); + boolean collectionExists = database.listCollectionNames() + .into(new ArrayList()) + .contains(testCollectionName); + + Boolean expectedStatus = true; + assertEquals(expectedStatus, collectionExists); + + } + + @Test + public void givenCount_whenCollectionAlreadyExists_thenCheckingForCollectionExistence() { + + MongoDatabase database = mongoClient.getDatabase(databaseName); + + MongoCollection collection = database.getCollection(testCollectionName); + Boolean collectionExists = collection.count() > 0 ? true : false; + + Boolean expectedStatus = false; + assertEquals(expectedStatus, collectionExists); + + } +} + diff --git a/persistence-modules/java-mongodb/src/test/java/com/baeldung/mongo/PushOperationLiveTest.java b/persistence-modules/java-mongodb/src/test/java/com/baeldung/mongo/PushOperationLiveTest.java new file mode 100644 index 0000000000..bd8523b301 --- /dev/null +++ b/persistence-modules/java-mongodb/src/test/java/com/baeldung/mongo/PushOperationLiveTest.java @@ -0,0 +1,92 @@ +package com.baeldung.mongo; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; + +import org.bson.Document; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +import com.mongodb.BasicDBObject; +import com.mongodb.DBObject; +import com.mongodb.MongoClient; +import com.mongodb.client.MongoCollection; +import com.mongodb.client.MongoDatabase; +import com.mongodb.client.model.Filters; +import com.mongodb.client.model.Updates; +import com.mongodb.client.result.UpdateResult; + +public class PushOperationLiveTest { + + private static MongoClient mongoClient; + private static MongoDatabase db; + private static MongoCollection collection; + + @BeforeClass + public static void setup() { + if (mongoClient == null) { + mongoClient = new MongoClient("localhost", 27017); + db = mongoClient.getDatabase("baeldung"); + collection = db.getCollection("orders"); + + collection.insertOne( + Document.parse("{\n" + " \"customerId\": 1023,\n" + " \"orderTimestamp\": NumberLong(\"1646460073000\"),\n" + " \"shippingDestination\": \"336, Street No.1 Pawai Mumbai\",\n" + " \"purchaseOrder\": 1000,\n" + + " \"contactNumber\":\"9898987676\",\n" + " \"items\": [ \n" + " {\n" + " \"itemName\": \"BERGER\",\n" + " \"quantity\": 1,\n" + " \"price\": 500\n" + " },\n" + + " {\n" + " \"itemName\": \"VEG PIZZA\",\n" + " \"quantity\": 1,\n" + " \"price\": 800\n" + " } \n" + " ]\n" + " }")); + } + } + + @Test + public void givenOrderCollection_whenPushOperationUsingDBObject_thenCheckingForDocument() { + + DBObject listItem = new BasicDBObject("items", new BasicDBObject("itemName", "PIZZA MANIA").append("quantity", 1) + .append("price", 800)); + BasicDBObject searchFilter = new BasicDBObject("customerId", 1023); + BasicDBObject updateQuery = new BasicDBObject(); + updateQuery.append("$push", listItem); + UpdateResult updateResult = collection.updateOne(searchFilter, updateQuery); + + Document orderDetail = collection.find(Filters.eq("customerId", 1023)) + .first(); + assertNotNull(orderDetail); + assertFalse(orderDetail.isEmpty()); + + } + + @Test + public void givenOrderCollection_whenPushOperationUsingDocument_thenCheckingForDocument() { + + Document item = new Document().append("itemName", "PIZZA MANIA") + .append("quantity", 1) + .append("price", 800); + UpdateResult updateResult = collection.updateOne(Filters.eq("customerId", 1023), Updates.push("items", item)); + + Document orderDetail = collection.find(Filters.eq("customerId", 1023)) + .first(); + assertNotNull(orderDetail); + assertFalse(orderDetail.isEmpty()); + + } + + @Test + public void givenOrderCollection_whenAddToSetOperation_thenCheckingForDocument() { + + Document item = new Document().append("itemName", "PIZZA MANIA") + .append("quantity", 1) + .append("price", 800); + UpdateResult updateResult = collection.updateOne(Filters.eq("customerId", 1023), Updates.addToSet("items", item)); + + Document orderDetail = collection.find(Filters.eq("customerId", 1023)) + .first(); + assertNotNull(orderDetail); + assertFalse(orderDetail.isEmpty()); + } + + @AfterClass + public static void cleanUp() { + mongoClient.close(); + } + +} + diff --git a/persistence-modules/java-mongodb/src/test/java/com/baeldung/update/UpdateFieldLiveTest.java b/persistence-modules/java-mongodb/src/test/java/com/baeldung/update/UpdateFieldLiveTest.java new file mode 100644 index 0000000000..47114e1f1a --- /dev/null +++ b/persistence-modules/java-mongodb/src/test/java/com/baeldung/update/UpdateFieldLiveTest.java @@ -0,0 +1,143 @@ +package com.baeldung.update; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; + +import org.bson.Document; +import org.junit.BeforeClass; +import org.junit.Test; + +import com.mongodb.MongoClient; +import com.mongodb.client.MongoCollection; +import com.mongodb.client.MongoDatabase; +import com.mongodb.client.model.Filters; +import com.mongodb.client.model.FindOneAndReplaceOptions; +import com.mongodb.client.model.FindOneAndUpdateOptions; +import com.mongodb.client.model.ReturnDocument; +import com.mongodb.client.model.Updates; +import com.mongodb.client.result.UpdateResult; + +public class UpdateFieldLiveTest { + + private static MongoClient mongoClient; + private static MongoDatabase db; + private static MongoCollection collection; + + @BeforeClass + public static void setup() { + if (mongoClient == null) { + mongoClient = new MongoClient("localhost", 27017); + db = mongoClient.getDatabase("baeldung"); + collection = db.getCollection("student"); + + collection.insertOne(Document.parse("{ \"student_id\": 8764,\"student_name\": \"Paul Starc\",\"address\": \"Hostel 1\",\"age\": 16,\"roll_no\":199406}")); + } + } + + @Test + public void updateOne() { + + UpdateResult updateResult = collection.updateOne(Filters.eq("student_name", "Paul Starc"), Updates.set("address", "Hostel 2")); + + Document studentDetail = collection.find(Filters.eq("student_name", "Paul Starc")) + .first(); + assertNotNull(studentDetail); + assertFalse(studentDetail.isEmpty()); + + String address = studentDetail.getString("address"); + String expectedAdderess = "Hostel 2"; + + assertEquals(expectedAdderess, address); + } + + @Test + public void updateMany() { + + UpdateResult updateResult = collection.updateMany(Filters.lt("age", 20), Updates.set("Review", true)); + + Document studentDetail = collection.find(Filters.eq("student_name", "Paul Starc")) + .first(); + assertNotNull(studentDetail); + assertFalse(studentDetail.isEmpty()); + + Boolean review = studentDetail.getBoolean("Review"); + Boolean expectedAdderess = true; + + assertEquals(expectedAdderess, review); + + } + + @Test + public void replaceOne() { + + Document replaceDocument = new Document(); + replaceDocument.append("student_id", 8764) + .append("student_name", "Paul Starc") + .append("address", "Hostel 3") + .append("age", 18) + .append("roll_no", 199406); + + UpdateResult updateResult = collection.replaceOne(Filters.eq("student_id", 8764), replaceDocument); + + Document studentDetail = collection.find(Filters.eq("student_name", "Paul Starc")) + .first(); + assertNotNull(studentDetail); + assertFalse(studentDetail.isEmpty()); + + Integer age = studentDetail.getInteger("age"); + Integer expectedAge = 18; + + assertEquals(expectedAge, age); + + } + + @Test + public void findOneAndReplace() { + + Document replaceDocument = new Document(); + replaceDocument.append("student_id", 8764) + .append("student_name", "Paul Starc") + .append("address", "Hostel 4") + .append("age", 18) + .append("roll_no", 199406); + Document sort = new Document("roll_no", 1); + Document projection = new Document("_id", 0).append("student_id", 1) + .append("address", 1); + Document resultDocument = collection.findOneAndReplace(Filters.eq("student_id", 8764), replaceDocument, new FindOneAndReplaceOptions().upsert(true) + .sort(sort) + .projection(projection) + .returnDocument(ReturnDocument.AFTER)); + + Document studentDetail = collection.find(Filters.eq("student_name", "Paul Starc")) + .first(); + assertNotNull(studentDetail); + assertFalse(studentDetail.isEmpty()); + + Integer age = studentDetail.getInteger("age"); + Integer expectedAge = 18; + + assertEquals(expectedAge, age); + + } + + @Test + public void findOneAndUpdate() { + + Document sort = new Document("roll_no", 1); + Document projection = new Document("_id", 0).append("student_id", 1) + .append("address", 1); + Document resultDocument = collection.findOneAndUpdate(Filters.eq("student_id", 8764), Updates.inc("roll_no", 5), new FindOneAndUpdateOptions().upsert(true) + .sort(sort) + .projection(projection) + .returnDocument(ReturnDocument.AFTER)); + + Document studentDetail = collection.find(Filters.eq("student_name", "Paul Starc")) + .first(); + assertNotNull(studentDetail); + assertFalse(studentDetail.isEmpty()); + + } + +} + diff --git a/persistence-modules/java-mongodb/src/test/java/com/baeldung/update/UpdateMultipleFieldsLiveTest.java b/persistence-modules/java-mongodb/src/test/java/com/baeldung/update/UpdateMultipleFieldsLiveTest.java index d1538d5312..d06de23423 100644 --- a/persistence-modules/java-mongodb/src/test/java/com/baeldung/update/UpdateMultipleFieldsLiveTest.java +++ b/persistence-modules/java-mongodb/src/test/java/com/baeldung/update/UpdateMultipleFieldsLiveTest.java @@ -2,8 +2,6 @@ package com.baeldung.update; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertSame; import org.bson.Document; import org.junit.Before; @@ -15,7 +13,6 @@ import com.mongodb.client.MongoCollection; import com.mongodb.client.MongoDatabase; import com.mongodb.client.model.Filters; import com.mongodb.client.model.Updates; -import com.mongodb.client.result.UpdateResult; public class UpdateMultipleFieldsLiveTest { @@ -30,8 +27,7 @@ public class UpdateMultipleFieldsLiveTest { db = mongoClient.getDatabase("baeldung"); collection = db.getCollection("employee"); - collection.insertOne(Document.parse( - "{'employee_id':794875,'employee_name': 'David smith','job': 'Sales Representative','department_id': 2,'salary': 20000,'hire_date': NumberLong(\"1643969311817\")}")); + collection.insertOne(Document.parse("{'employee_id':794875,'employee_name': 'David Smith','job': 'Sales Representative','department_id': 2,'salary': 20000,'hire_date': NumberLong(\"1643969311817\")}")); } } @@ -47,7 +43,8 @@ public class UpdateMultipleFieldsLiveTest { collection.updateMany(searchQuery, setQuery); - Document nameDoc = collection.find(Filters.eq("employee_id", 794875)).first(); + Document nameDoc = collection.find(Filters.eq("employee_id", 794875)) + .first(); assertNotNull(nameDoc); assertFalse(nameDoc.isEmpty()); @@ -62,10 +59,10 @@ public class UpdateMultipleFieldsLiveTest { @Test public void updateMultipleFieldsUsingDocument() { - collection.updateMany(Filters.eq("employee_id", 794875), - Updates.combine(Updates.set("department_id", 4), Updates.set("job", "Sales Manager"))); + collection.updateMany(Filters.eq("employee_id", 794875), Updates.combine(Updates.set("department_id", 4), Updates.set("job", "Sales Manager"))); - Document nameDoc = collection.find(Filters.eq("employee_id", 794875)).first(); + Document nameDoc = collection.find(Filters.eq("employee_id", 794875)) + .first(); assertNotNull(nameDoc); assertFalse(nameDoc.isEmpty()); @@ -78,3 +75,4 @@ public class UpdateMultipleFieldsLiveTest { } } + diff --git a/pom.xml b/pom.xml index edc5302390..b6767c629b 100644 --- a/pom.xml +++ b/pom.xml @@ -462,6 +462,7 @@ jaxb jee-7 jee-7-security + jakarta-ee jersey jgit jgroups @@ -518,7 +519,7 @@ micronaut microprofile msf4j - + muleesb mustache mybatis @@ -555,9 +556,9 @@ rxjava-observables rxjava-operators - atomikos - reactive-systems - slack + atomikos + reactive-systems + slack @@ -945,6 +946,7 @@ jaxb jee-7 jee-7-security + jakarta-ee jersey jgit jgroups @@ -1001,7 +1003,7 @@ micronaut microprofile msf4j - + muleesb mustache mybatis @@ -1038,9 +1040,9 @@ rxjava-observables rxjava-operators - atomikos - reactive-systems - slack + atomikos + reactive-systems + slack @@ -1311,42 +1313,43 @@ - core-java-modules/core-java-9 - core-java-modules/core-java-9-improvements - core-java-modules/core-java-9-jigsaw + core-java-modules/core-java-9 + core-java-modules/core-java-9-improvements + core-java-modules/core-java-9-jigsaw - core-java-modules/core-java-9-streams - core-java-modules/core-java-10 - core-java-modules/core-java-11 - core-java-modules/core-java-11-2 - - - - - core-java-modules/core-java-collections-set - core-java-modules/core-java-collections-maps-4 - core-java-modules/core-java-date-operations-1 - core-java-modules/core-java-datetime-conversion - core-java-modules/core-java-datetime-string - core-java-modules/core-java-io-conversions-2 - core-java-modules/core-java-jpms - core-java-modules/core-java-os - core-java-modules/core-java-string-algorithms-3 - core-java-modules/core-java-string-operations-3 - core-java-modules/core-java-string-operations-4 - core-java-modules/core-java-time-measurements - core-java-modules/core-java-networking-3 - core-java-modules/multimodulemavenproject - ddd-modules - httpclient-2 - libraries-concurrency - persistence-modules/sirix - persistence-modules/spring-data-cassandra-2 - quarkus-vs-springboot - quarkus-jandex - spring-boot-modules/spring-boot-cassandre - spring-boot-modules/spring-boot-camel - testing-modules/testing-assertions + core-java-modules/core-java-9-streams + core-java-modules/core-java-10 + core-java-modules/core-java-11 + core-java-modules/core-java-11-2 + + + + + core-java-modules/core-java-collections-set + core-java-modules/core-java-collections-maps-4 + core-java-modules/core-java-date-operations-1 + core-java-modules/core-java-datetime-conversion + core-java-modules/core-java-datetime-string + core-java-modules/core-java-io-conversions-2 + core-java-modules/core-java-jpms + core-java-modules/core-java-os + core-java-modules/core-java-string-algorithms-3 + core-java-modules/core-java-string-operations-3 + core-java-modules/core-java-string-operations-4 + core-java-modules/core-java-time-measurements + core-java-modules/core-java-networking-3 + core-java-modules/multimodulemavenproject + ddd-modules + httpclient-2 + libraries-concurrency + persistence-modules/sirix + persistence-modules/spring-data-cassandra-2 + quarkus-vs-springboot + quarkus-jandex + spring-boot-modules/spring-boot-cassandre + spring-boot-modules/spring-boot-camel + testing-modules/testing-assertions + persistence-modules/fauna @@ -1409,6 +1412,7 @@ spring-boot-modules/spring-boot-cassandre spring-boot-modules/spring-boot-camel testing-modules/testing-assertions + persistence-modules/fauna diff --git a/spring-5-autowiring-beans/README.md b/spring-5-autowiring-beans/README.md deleted file mode 100644 index dc8751325e..0000000000 --- a/spring-5-autowiring-beans/README.md +++ /dev/null @@ -1,3 +0,0 @@ -### Relevant Articles: - -- [Spring @Autowired Field Null – Common Causes and Solutions](https://www.baeldung.com/spring-autowired-field-null) diff --git a/spring-5-autowiring-beans/pom.xml b/spring-5-autowiring-beans/pom.xml deleted file mode 100644 index 32b56cc9ad..0000000000 --- a/spring-5-autowiring-beans/pom.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - 4.0.0 - spring-5-autowiring-beans - 0.0.1-SNAPSHOT - spring-5-autowiring-beans - - - com.baeldung - parent-boot-2 - 0.0.1-SNAPSHOT - ../parent-boot-2 - - - - - org.springframework.boot - spring-boot-starter-web - - - - diff --git a/spring-5-autowiring-beans/src/main/java/com/baeldung/autowiring/controller/CorrectController.java b/spring-5-autowiring-beans/src/main/java/com/baeldung/autowiring/controller/CorrectController.java deleted file mode 100644 index e0c0d7eeac..0000000000 --- a/spring-5-autowiring-beans/src/main/java/com/baeldung/autowiring/controller/CorrectController.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.baeldung.autowiring.controller; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Controller; - -import com.baeldung.autowiring.service.MyService; - -@Controller -public class CorrectController { - - @Autowired - MyService myService; - - public String control() { - return myService.serve(); - } - -} diff --git a/spring-5-autowiring-beans/src/main/java/com/baeldung/autowiring/controller/FlawedController.java b/spring-5-autowiring-beans/src/main/java/com/baeldung/autowiring/controller/FlawedController.java deleted file mode 100644 index 673e686f79..0000000000 --- a/spring-5-autowiring-beans/src/main/java/com/baeldung/autowiring/controller/FlawedController.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.baeldung.autowiring.controller; - -import org.springframework.stereotype.Controller; - -import com.baeldung.autowiring.service.MyService; - -@Controller -public class FlawedController { - - public String control() { - MyService userService = new MyService(); - return userService.serve(); - } - -} diff --git a/spring-5-autowiring-beans/src/main/java/com/baeldung/autowiring/service/MyComponent.java b/spring-5-autowiring-beans/src/main/java/com/baeldung/autowiring/service/MyComponent.java deleted file mode 100644 index c04ca3f4ba..0000000000 --- a/spring-5-autowiring-beans/src/main/java/com/baeldung/autowiring/service/MyComponent.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.baeldung.autowiring.service; - -import org.springframework.stereotype.Component; - -@Component -public class MyComponent { - - public void doWork() {} - -} diff --git a/spring-5-autowiring-beans/src/main/java/com/baeldung/autowiring/service/MyService.java b/spring-5-autowiring-beans/src/main/java/com/baeldung/autowiring/service/MyService.java deleted file mode 100644 index 3443dc05de..0000000000 --- a/spring-5-autowiring-beans/src/main/java/com/baeldung/autowiring/service/MyService.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.baeldung.autowiring.service; - -import org.springframework.beans.factory.annotation.Autowired; - -/** - * The bean corresponding to this class is defined in MyServiceConfiguration - * Alternatively, you could choose to decorate this class with @Component or @Service - */ -public class MyService { - - @Autowired - MyComponent myComponent; - - public String serve() { - myComponent.doWork(); - return "success"; - } - -} diff --git a/spring-5-autowiring-beans/src/main/java/com/baeldung/autowiring/service/MyServiceConfiguration.java b/spring-5-autowiring-beans/src/main/java/com/baeldung/autowiring/service/MyServiceConfiguration.java deleted file mode 100644 index e30e4f770e..0000000000 --- a/spring-5-autowiring-beans/src/main/java/com/baeldung/autowiring/service/MyServiceConfiguration.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.baeldung.autowiring.service; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -@Configuration -public class MyServiceConfiguration { - - @Bean - MyService myService() { - return new MyService(); - } - -} diff --git a/spring-5-autowiring-beans/src/test/java/com/baeldung/autowiring/controller/CorrectControllerIntegrationTest.java b/spring-5-autowiring-beans/src/test/java/com/baeldung/autowiring/controller/CorrectControllerIntegrationTest.java deleted file mode 100644 index 3807641edd..0000000000 --- a/spring-5-autowiring-beans/src/test/java/com/baeldung/autowiring/controller/CorrectControllerIntegrationTest.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.baeldung.autowiring.controller; - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit.jupiter.SpringExtension; - -import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; - -@ExtendWith(SpringExtension.class) -@SpringBootTest -public class CorrectControllerIntegrationTest { - - @Autowired - CorrectController controller; - - @Test - void whenControl_ThenRunSuccessfully() { - assertDoesNotThrow(() -> controller.control()); - } - -} diff --git a/spring-5-autowiring-beans/src/test/java/com/baeldung/autowiring/controller/FlawedControllerIntegrationTest.java b/spring-5-autowiring-beans/src/test/java/com/baeldung/autowiring/controller/FlawedControllerIntegrationTest.java deleted file mode 100644 index 79d446604f..0000000000 --- a/spring-5-autowiring-beans/src/test/java/com/baeldung/autowiring/controller/FlawedControllerIntegrationTest.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.baeldung.autowiring.controller; - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -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.test.context.junit.jupiter.SpringExtension; - -import static org.junit.jupiter.api.Assertions.assertThrows; - -@ExtendWith(SpringExtension.class) -@SpringBootTest -public class FlawedControllerIntegrationTest { - - private static final Logger LOGGER = LoggerFactory.getLogger(FlawedControllerIntegrationTest.class); - - @Autowired - FlawedController myController; - - @Test - void whenControl_ThenThrowNullPointerException() { - NullPointerException npe = assertThrows(NullPointerException.class, () -> myController.control()); - LOGGER.error("Got a NullPointerException", npe); - } - -} diff --git a/spring-boot-modules/spring-boot-keycloak/src/main/java/com/baeldung/keycloak/KeycloakConfig.java b/spring-boot-modules/spring-boot-keycloak/src/main/java/com/baeldung/keycloak/KeycloakConfig.java new file mode 100644 index 0000000000..6a3dc45717 --- /dev/null +++ b/spring-boot-modules/spring-boot-keycloak/src/main/java/com/baeldung/keycloak/KeycloakConfig.java @@ -0,0 +1,14 @@ +package com.baeldung.keycloak; + +import org.keycloak.adapters.springboot.KeycloakSpringBootConfigResolver; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class KeycloakConfig { + + @Bean + public KeycloakSpringBootConfigResolver keycloakConfigResolver() { + return new KeycloakSpringBootConfigResolver(); + } +} diff --git a/spring-boot-modules/spring-boot-keycloak/src/main/java/com/baeldung/keycloak/SecurityConfig.java b/spring-boot-modules/spring-boot-keycloak/src/main/java/com/baeldung/keycloak/SecurityConfig.java index 78023aff8f..826f475a6e 100644 --- a/spring-boot-modules/spring-boot-keycloak/src/main/java/com/baeldung/keycloak/SecurityConfig.java +++ b/spring-boot-modules/spring-boot-keycloak/src/main/java/com/baeldung/keycloak/SecurityConfig.java @@ -23,11 +23,6 @@ class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter { auth.authenticationProvider(keycloakAuthenticationProvider); } - @Bean - public KeycloakSpringBootConfigResolver KeycloakConfigResolver() { - return new KeycloakSpringBootConfigResolver(); - } - // Specifies the session authentication strategy @Bean @Override diff --git a/spring-cloud/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/fileupload/config/ExceptionMessage.java b/spring-cloud/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/fileupload/config/ExceptionMessage.java new file mode 100644 index 0000000000..45a555b2ea --- /dev/null +++ b/spring-cloud/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/fileupload/config/ExceptionMessage.java @@ -0,0 +1,55 @@ +package com.baeldung.cloud.openfeign.fileupload.config; + +public class ExceptionMessage { + private String timestamp; + private int status; + private String error; + private String message; + private String path; + + public String getTimestamp() { + return timestamp; + } + + public void setTimestamp(String timestamp) { + this.timestamp = timestamp; + } + + public int getStatus() { + return status; + } + + public void setStatus(int status) { + this.status = status; + } + + public String getError() { + return error; + } + + public void setError(String error) { + this.error = error; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } + + @Override + public String toString() { + return "ExceptionMessage [timestamp=" + timestamp + ", status=" + status + ", error=" + error + ", message=" + message + ", path=" + path + "]"; + } + +} diff --git a/spring-cloud/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/fileupload/config/FeignSupportConfig.java b/spring-cloud/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/fileupload/config/FeignSupportConfig.java index 943134213a..802077a3d7 100644 --- a/spring-cloud/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/fileupload/config/FeignSupportConfig.java +++ b/spring-cloud/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/fileupload/config/FeignSupportConfig.java @@ -7,6 +7,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.web.client.RestTemplate; import feign.codec.Encoder; +import feign.codec.ErrorDecoder; import feign.form.spring.SpringFormEncoder; public class FeignSupportConfig { @@ -19,4 +20,9 @@ public class FeignSupportConfig { } })); } + + @Bean + public ErrorDecoder errorDecoder() { + return new RetreiveMessageErrorDecoder(); + } } diff --git a/spring-cloud/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/fileupload/config/RetreiveMessageErrorDecoder.java b/spring-cloud/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/fileupload/config/RetreiveMessageErrorDecoder.java new file mode 100644 index 0000000000..09bf8bf54b --- /dev/null +++ b/spring-cloud/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/fileupload/config/RetreiveMessageErrorDecoder.java @@ -0,0 +1,35 @@ +package com.baeldung.cloud.openfeign.fileupload.config; + +import java.io.IOException; +import java.io.InputStream; + +import com.baeldung.cloud.openfeign.exception.BadRequestException; +import com.baeldung.cloud.openfeign.exception.NotFoundException; +import com.fasterxml.jackson.databind.ObjectMapper; + +import feign.Response; +import feign.codec.ErrorDecoder; + +public class RetreiveMessageErrorDecoder implements ErrorDecoder { + private final ErrorDecoder errorDecoder = new Default(); + + @Override + public Exception decode(String methodKey, Response response) { + ExceptionMessage message = null; + try (InputStream bodyIs = response.body() + .asInputStream()) { + ObjectMapper mapper = new ObjectMapper(); + message = mapper.readValue(bodyIs, ExceptionMessage.class); + } catch (IOException e) { + return new Exception(e.getMessage()); + } + switch (response.status()) { + case 400: + return new BadRequestException(message.getMessage() != null ? message.getMessage() : "Bad Request"); + case 404: + return new NotFoundException(message.getMessage() != null ? message.getMessage() : "Not found"); + default: + return errorDecoder.decode(methodKey, response); + } + } +} diff --git a/spring-cloud/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/fileupload/controller/FileController.java b/spring-cloud/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/fileupload/controller/FileController.java index ebdf7ff6c8..1ddbfcea81 100644 --- a/spring-cloud/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/fileupload/controller/FileController.java +++ b/spring-cloud/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/fileupload/controller/FileController.java @@ -25,4 +25,9 @@ public class FileController { return service.uploadFileWithManualClient(file); } + @PostMapping(value = "/upload-error") + public String handleFileUploadError(@RequestPart(value = "file") MultipartFile file) { + return service.uploadFile(file); + } + } \ No newline at end of file diff --git a/spring-cloud/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/fileupload/service/UploadClient.java b/spring-cloud/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/fileupload/service/UploadClient.java index 63d17130e9..8f3ef7e421 100644 --- a/spring-cloud/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/fileupload/service/UploadClient.java +++ b/spring-cloud/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/fileupload/service/UploadClient.java @@ -12,4 +12,7 @@ import com.baeldung.cloud.openfeign.fileupload.config.FeignSupportConfig; public interface UploadClient { @PostMapping(value = "/upload-file", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) String fileUpload(@RequestPart(value = "file") MultipartFile file); + + @PostMapping(value = "/upload-file-error", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) + String fileUploadError(@RequestPart(value = "file") MultipartFile file); } diff --git a/spring-cloud/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/fileupload/service/UploadService.java b/spring-cloud/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/fileupload/service/UploadService.java index 7dd7f5a89c..742a37668b 100644 --- a/spring-cloud/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/fileupload/service/UploadService.java +++ b/spring-cloud/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/fileupload/service/UploadService.java @@ -26,4 +26,8 @@ public class UploadService { return client.fileUpload(file); } + public String uploadFileError(MultipartFile file) { + return client.fileUpload(file); + } + } \ No newline at end of file diff --git a/spring-security-modules/spring-5-security-oauth/README.md b/spring-security-modules/spring-5-security-oauth/README.md index 35e64da639..e5b149fee6 100644 --- a/spring-security-modules/spring-5-security-oauth/README.md +++ b/spring-security-modules/spring-5-security-oauth/README.md @@ -8,3 +8,4 @@ This module contains articles about Spring 5 OAuth Security - [Extracting Principal and Authorities using Spring Security OAuth](https://www.baeldung.com/spring-security-oauth-principal-authorities-extractor) - [Customizing Authorization and Token Requests with Spring Security 5.1 Client](https://www.baeldung.com/spring-security-custom-oauth-requests) - [Social Login with Spring Security in a Jersey Application](https://www.baeldung.com/spring-security-social-login-jersey) +- [Introduction to OAuth2RestTemplate](https://www.baeldung.com/spring-oauth2resttemplate) diff --git a/spring-security-modules/spring-5-security-oauth/src/main/java/com/baeldung/oauth2resttemplate/AppController.java b/spring-security-modules/spring-5-security-oauth/src/main/java/com/baeldung/oauth2resttemplate/AppController.java new file mode 100644 index 0000000000..3c3efd950f --- /dev/null +++ b/spring-security-modules/spring-5-security-oauth/src/main/java/com/baeldung/oauth2resttemplate/AppController.java @@ -0,0 +1,32 @@ +package com.baeldung.oauth2resttemplate; + +import org.springframework.security.oauth2.client.OAuth2RestTemplate; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; + +import java.security.Principal; +import java.util.Collection; + +@Controller +public class AppController { + + OAuth2RestTemplate restTemplate; + + public AppController(OAuth2RestTemplate restTemplate) { + this.restTemplate = restTemplate; + } + + @GetMapping("/home") + public String welcome(Model model, Principal principal) { + model.addAttribute("name", principal.getName()); + return "home"; + } + + @GetMapping("/repos") + public String repos(Model model) { + Collection repos = restTemplate.getForObject("https://api.github.com/user/repos", Collection.class); + model.addAttribute("repos", repos); + return "repositories"; + } +} diff --git a/spring-security-modules/spring-5-security-oauth/src/main/java/com/baeldung/oauth2resttemplate/GithubRepo.java b/spring-security-modules/spring-5-security-oauth/src/main/java/com/baeldung/oauth2resttemplate/GithubRepo.java new file mode 100644 index 0000000000..48cc05c1de --- /dev/null +++ b/spring-security-modules/spring-5-security-oauth/src/main/java/com/baeldung/oauth2resttemplate/GithubRepo.java @@ -0,0 +1,22 @@ +package com.baeldung.oauth2resttemplate; + +public class GithubRepo { + Long id; + String name; + + 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; + } +} diff --git a/spring-security-modules/spring-5-security-oauth/src/main/java/com/baeldung/oauth2resttemplate/SecurityConfig.java b/spring-security-modules/spring-5-security-oauth/src/main/java/com/baeldung/oauth2resttemplate/SecurityConfig.java new file mode 100644 index 0000000000..fa274d1c9b --- /dev/null +++ b/spring-security-modules/spring-5-security-oauth/src/main/java/com/baeldung/oauth2resttemplate/SecurityConfig.java @@ -0,0 +1,73 @@ +package com.baeldung.oauth2resttemplate; + +import org.springframework.boot.autoconfigure.security.oauth2.resource.ResourceServerProperties; +import org.springframework.boot.autoconfigure.security.oauth2.resource.UserInfoTokenServices; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.Ordered; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.oauth2.client.OAuth2ClientContext; +import org.springframework.security.oauth2.client.OAuth2RestTemplate; +import org.springframework.security.oauth2.client.filter.OAuth2ClientAuthenticationProcessingFilter; +import org.springframework.security.oauth2.client.filter.OAuth2ClientContextFilter; +import org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeResourceDetails; +import org.springframework.security.oauth2.config.annotation.web.configuration.EnableOAuth2Client; +import org.springframework.security.web.authentication.www.BasicAuthenticationFilter; + +import javax.servlet.Filter; + +@Configuration +@EnableOAuth2Client +public class SecurityConfig extends WebSecurityConfigurerAdapter { + OAuth2ClientContext oauth2ClientContext; + + public SecurityConfig(OAuth2ClientContext oauth2ClientContext) { + this.oauth2ClientContext = oauth2ClientContext; + } + + @Override + protected void configure(HttpSecurity http) throws Exception { + http.authorizeRequests().antMatchers("/", "/login**", "/error**") + .permitAll().anyRequest().authenticated() + .and().logout().logoutUrl("/logout").logoutSuccessUrl("/") + .and().addFilterBefore(oauth2ClientFilter(), BasicAuthenticationFilter.class); + } + + @Bean + public FilterRegistrationBean oauth2ClientFilterRegistration(OAuth2ClientContextFilter filter) { + FilterRegistrationBean registration = new FilterRegistrationBean<>(); + registration.setFilter(filter); + registration.setOrder(Ordered.HIGHEST_PRECEDENCE + 1); + return registration; + } + + @Bean + public OAuth2RestTemplate restTemplate() { + return new OAuth2RestTemplate(githubClient(), oauth2ClientContext); + } + + @Bean + @ConfigurationProperties("github.client") + public AuthorizationCodeResourceDetails githubClient() { + return new AuthorizationCodeResourceDetails(); + } + + private Filter oauth2ClientFilter() { + OAuth2ClientAuthenticationProcessingFilter oauth2ClientFilter = new OAuth2ClientAuthenticationProcessingFilter("/login/github"); + OAuth2RestTemplate restTemplate = restTemplate(); + oauth2ClientFilter.setRestTemplate(restTemplate); + UserInfoTokenServices tokenServices = new UserInfoTokenServices(githubResource().getUserInfoUri(), githubClient().getClientId()); + tokenServices.setRestTemplate(restTemplate); + oauth2ClientFilter.setTokenServices(tokenServices); + return oauth2ClientFilter; + } + + @Bean + @ConfigurationProperties("github.resource") + public ResourceServerProperties githubResource() { + return new ResourceServerProperties(); + } +} diff --git a/spring-security-modules/spring-5-security-oauth/src/main/java/com/baeldung/oauth2resttemplate/SpringSecurityOauth2ClientApplication.java b/spring-security-modules/spring-5-security-oauth/src/main/java/com/baeldung/oauth2resttemplate/SpringSecurityOauth2ClientApplication.java new file mode 100644 index 0000000000..846169e5bf --- /dev/null +++ b/spring-security-modules/spring-5-security-oauth/src/main/java/com/baeldung/oauth2resttemplate/SpringSecurityOauth2ClientApplication.java @@ -0,0 +1,15 @@ +package com.baeldung.oauth2resttemplate; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.PropertySource; + +@SpringBootApplication +@PropertySource("classpath:application-oauth2-rest-template.properties") +public class SpringSecurityOauth2ClientApplication { + + public static void main(String[] args) { + SpringApplication.run(SpringSecurityOauth2ClientApplication.class, args); + } + +} diff --git a/spring-security-modules/spring-5-security-oauth/src/main/resources/application-oauth2-rest-template.properties b/spring-security-modules/spring-5-security-oauth/src/main/resources/application-oauth2-rest-template.properties new file mode 100644 index 0000000000..15d34b76be --- /dev/null +++ b/spring-security-modules/spring-5-security-oauth/src/main/resources/application-oauth2-rest-template.properties @@ -0,0 +1,9 @@ +github.client.clientId=[CLIENT_ID] +github.client.clientSecret=[CLIENT_SECRET] +github.client.userAuthorizationUri=https://github.com/login/oauth/authorize +github.client.accessTokenUri=https://github.com/login/oauth/access_token +github.client.clientAuthenticationScheme=form + +github.resource.userInfoUri=https://api.github.com/user + +spring.thymeleaf.prefix=classpath:/templates/oauth2resttemplate/ \ No newline at end of file diff --git a/spring-security-modules/spring-5-security-oauth/src/main/resources/templates/oauth2resttemplate/error.html b/spring-security-modules/spring-5-security-oauth/src/main/resources/templates/oauth2resttemplate/error.html new file mode 100644 index 0000000000..45bcddf654 --- /dev/null +++ b/spring-security-modules/spring-5-security-oauth/src/main/resources/templates/oauth2resttemplate/error.html @@ -0,0 +1,9 @@ + + + + Error + + +

An error occurred.

+ + \ No newline at end of file diff --git a/spring-security-modules/spring-5-security-oauth/src/main/resources/templates/oauth2resttemplate/home.html b/spring-security-modules/spring-5-security-oauth/src/main/resources/templates/oauth2resttemplate/home.html new file mode 100644 index 0000000000..3eba3615d6 --- /dev/null +++ b/spring-security-modules/spring-5-security-oauth/src/main/resources/templates/oauth2resttemplate/home.html @@ -0,0 +1,18 @@ + + + + Home + + +

+ Welcome [[${name}]] +

+

+ View Repositories

+

+ +
+ +
+ + \ No newline at end of file diff --git a/spring-security-modules/spring-5-security-oauth/src/main/resources/templates/oauth2resttemplate/index.html b/spring-security-modules/spring-5-security-oauth/src/main/resources/templates/oauth2resttemplate/index.html new file mode 100644 index 0000000000..4db3b78d23 --- /dev/null +++ b/spring-security-modules/spring-5-security-oauth/src/main/resources/templates/oauth2resttemplate/index.html @@ -0,0 +1,16 @@ + + + + OAuth2Client + + +

+ + Go to Home + + + GitHub Login + +

+ + \ No newline at end of file diff --git a/spring-security-modules/spring-5-security-oauth/src/main/resources/templates/oauth2resttemplate/repositories.html b/spring-security-modules/spring-5-security-oauth/src/main/resources/templates/oauth2resttemplate/repositories.html new file mode 100644 index 0000000000..1eabf2270f --- /dev/null +++ b/spring-security-modules/spring-5-security-oauth/src/main/resources/templates/oauth2resttemplate/repositories.html @@ -0,0 +1,14 @@ + + + + Repositories + + +

+

Repos

+

+
    +
  • +
+ + \ No newline at end of file diff --git a/spring-security-modules/spring-security-web-boot-3/pom.xml b/spring-security-modules/spring-security-web-boot-3/pom.xml index 5f2a455294..5da993acd9 100644 --- a/spring-security-modules/spring-security-web-boot-3/pom.xml +++ b/spring-security-modules/spring-security-web-boot-3/pom.xml @@ -1,5 +1,6 @@ - + 4.0.0 spring-security-web-boot-3 0.0.1-SNAPSHOT @@ -23,6 +24,15 @@ org.springframework.boot spring-boot-starter-web + + org.springframework.boot + spring-boot-starter-data-mongodb + + + de.flapdoodle.embed + de.flapdoodle.embed.mongo + 3.3.1 + commons-io commons-io diff --git a/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/mongoauth/MongoAuthApplication.java b/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/mongoauth/MongoAuthApplication.java new file mode 100644 index 0000000000..53624c0dd8 --- /dev/null +++ b/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/mongoauth/MongoAuthApplication.java @@ -0,0 +1,18 @@ +package com.baeldung.mongoauth; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Import; + +import com.baeldung.mongoauth.config.MongoConfig; +import com.baeldung.mongoauth.config.SecurityConfig; + +@SpringBootApplication +@Import({ SecurityConfig.class, MongoConfig.class }) +public class MongoAuthApplication { + + public static void main(String... args) { + SpringApplication.run(MongoAuthApplication.class, args); + } + +} diff --git a/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/mongoauth/config/MongoConfig.java b/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/mongoauth/config/MongoConfig.java new file mode 100644 index 0000000000..ddef7800de --- /dev/null +++ b/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/mongoauth/config/MongoConfig.java @@ -0,0 +1,40 @@ +package com.baeldung.mongoauth.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.util.SocketUtils; + +import com.mongodb.client.MongoClients; + +import de.flapdoodle.embed.mongo.MongodExecutable; +import de.flapdoodle.embed.mongo.MongodStarter; +import de.flapdoodle.embed.mongo.config.ImmutableMongodConfig; +import de.flapdoodle.embed.mongo.config.MongodConfig; +import de.flapdoodle.embed.mongo.config.Net; +import de.flapdoodle.embed.mongo.distribution.Version; +import de.flapdoodle.embed.process.runtime.Network; + +@Configuration +public class MongoConfig { + + private static final String CONNECTION_STRING = "mongodb://%s:%d"; + private static final String HOST = "localhost"; + + @Bean + public MongoTemplate mongoTemplate() throws Exception { + + int randomPort = SocketUtils.findAvailableTcpPort(); + + ImmutableMongodConfig mongoDbConfig = MongodConfig.builder() + .version(Version.Main.PRODUCTION) + .net(new Net(HOST, randomPort, Network.localhostIsIPv6())) + .build(); + + MongodStarter starter = MongodStarter.getDefaultInstance(); + MongodExecutable mongodExecutable = starter.prepare(mongoDbConfig); + mongodExecutable.start(); + return new MongoTemplate(MongoClients.create(String.format(CONNECTION_STRING, HOST, randomPort)), "mongo_auth"); + } + +} diff --git a/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/mongoauth/config/SecurityConfig.java b/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/mongoauth/config/SecurityConfig.java new file mode 100644 index 0000000000..050d917492 --- /dev/null +++ b/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/mongoauth/config/SecurityConfig.java @@ -0,0 +1,59 @@ +package com.baeldung.mongoauth.config; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; + +@Configuration +@EnableWebSecurity +@EnableGlobalMethodSecurity(securedEnabled = true, jsr250Enabled = true) +public class SecurityConfig extends WebSecurityConfigurerAdapter { + + private final UserDetailsService userDetailsService; + + public SecurityConfig(UserDetailsService userDetailsService) { + this.userDetailsService = userDetailsService; + } + + @Bean + public AuthenticationManager customAuthenticationManager() throws Exception { + return authenticationManager(); + } + + @Bean + public BCryptPasswordEncoder bCryptPasswordEncoder() { + return new BCryptPasswordEncoder(); + } + + @Override + protected void configure(@Autowired AuthenticationManagerBuilder auth) throws Exception { + auth.userDetailsService(userDetailsService) + .passwordEncoder(bCryptPasswordEncoder()); + } + + @Override + protected void configure(HttpSecurity http) throws Exception { + http.csrf() + .disable() + .authorizeRequests() + .and() + .httpBasic() + .and() + .authorizeRequests() + .anyRequest() + .permitAll() + .and() + .sessionManagement() + .sessionCreationPolicy(SessionCreationPolicy.STATELESS); + } + +} diff --git a/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/mongoauth/controller/ResourceController.java b/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/mongoauth/controller/ResourceController.java new file mode 100644 index 0000000000..a5d9e91083 --- /dev/null +++ b/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/mongoauth/controller/ResourceController.java @@ -0,0 +1,23 @@ +package com.baeldung.mongoauth.controller; + +import javax.annotation.security.RolesAllowed; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class ResourceController { + + @RolesAllowed("ROLE_ADMIN") + @GetMapping("/admin") + public String admin() { + return "Hello Admin!"; + } + + @RolesAllowed({ "ROLE_ADMIN", "ROLE_USER" }) + @GetMapping("/user") + public String user() { + return "Hello User!"; + } + +} diff --git a/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/mongoauth/domain/Role.java b/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/mongoauth/domain/Role.java new file mode 100644 index 0000000000..e475e68460 --- /dev/null +++ b/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/mongoauth/domain/Role.java @@ -0,0 +1,13 @@ +package com.baeldung.mongoauth.domain; + +public class Role { + private String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/mongoauth/domain/User.java b/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/mongoauth/domain/User.java new file mode 100644 index 0000000000..ffaea836a4 --- /dev/null +++ b/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/mongoauth/domain/User.java @@ -0,0 +1,83 @@ +package com.baeldung.mongoauth.domain; + +import java.util.Objects; +import java.util.Set; + +import org.bson.types.ObjectId; +import org.springframework.data.mongodb.core.mapping.Document; +import org.springframework.data.mongodb.core.mapping.MongoId; +import org.springframework.security.core.userdetails.UserDetails; + +@Document +public class User implements UserDetails { + private @MongoId ObjectId id; + private String username; + private String password; + private Set userRoles; + + public ObjectId getId() { + return id; + } + + @Override + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public void setUserRoles(Set userRoles) { + this.userRoles = userRoles; + } + + @Override + public Set getAuthorities() { + return this.userRoles; + } + + @Override + public String getUsername() { + return this.username; + } + + public void setUsername(String username) { + this.username = username; + } + + @Override + public boolean isAccountNonExpired() { + return false; + } + + @Override + public boolean isAccountNonLocked() { + return false; + } + + @Override + public boolean isCredentialsNonExpired() { + return false; + } + + @Override + public boolean isEnabled() { + return false; + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + User user = (User) o; + return Objects.equals(username, user.username); + } + + @Override + public int hashCode() { + return Objects.hash(username); + } +} diff --git a/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/mongoauth/domain/UserRole.java b/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/mongoauth/domain/UserRole.java new file mode 100644 index 0000000000..ccfa3bd605 --- /dev/null +++ b/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/mongoauth/domain/UserRole.java @@ -0,0 +1,21 @@ +package com.baeldung.mongoauth.domain; + +import org.springframework.security.core.GrantedAuthority; + +public class UserRole implements GrantedAuthority { + + private Role role; + + @Override + public String getAuthority() { + return role.getName(); + } + + public Role getRole() { + return role; + } + + public void setRole(Role role) { + this.role = role; + } +} diff --git a/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/mongoauth/repository/UserRepository.java b/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/mongoauth/repository/UserRepository.java new file mode 100644 index 0000000000..c68f77ffbf --- /dev/null +++ b/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/mongoauth/repository/UserRepository.java @@ -0,0 +1,13 @@ +package com.baeldung.mongoauth.repository; + +import org.springframework.data.mongodb.repository.MongoRepository; +import org.springframework.data.mongodb.repository.Query; + +import com.baeldung.mongoauth.domain.User; + +public interface UserRepository extends MongoRepository { + + @Query("{username:'?0'}") + User findUserByUsername(String username); + +} diff --git a/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/mongoauth/service/MongoAuthUserDetailService.java b/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/mongoauth/service/MongoAuthUserDetailService.java new file mode 100644 index 0000000000..5838504d40 --- /dev/null +++ b/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/mongoauth/service/MongoAuthUserDetailService.java @@ -0,0 +1,41 @@ +package com.baeldung.mongoauth.service; + +import java.util.HashSet; +import java.util.Set; + +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.userdetails.User; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.stereotype.Service; + +import com.baeldung.mongoauth.repository.UserRepository; + +@Service +public class MongoAuthUserDetailService implements UserDetailsService { + + private final UserRepository userRepository; + + public MongoAuthUserDetailService(UserRepository userRepository) { + this.userRepository = userRepository; + } + + @Override + public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException { + + com.baeldung.mongoauth.domain.User user = userRepository.findUserByUsername(userName); + + Set grantedAuthorities = new HashSet<>(); + + user.getAuthorities() + .forEach(role -> { + grantedAuthorities.add(new SimpleGrantedAuthority(role.getRole() + .getName())); + }); + + return new User(user.getUsername(), user.getPassword(), grantedAuthorities); + } + +} diff --git a/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/mongoauth/service/SecurityService.java b/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/mongoauth/service/SecurityService.java new file mode 100644 index 0000000000..4204e4708b --- /dev/null +++ b/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/mongoauth/service/SecurityService.java @@ -0,0 +1,5 @@ +package com.baeldung.mongoauth.service; + +public interface SecurityService { + boolean login(String username, String password); +} diff --git a/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/mongoauth/service/SecurityServiceImpl.java b/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/mongoauth/service/SecurityServiceImpl.java new file mode 100644 index 0000000000..f86ffaa26a --- /dev/null +++ b/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/mongoauth/service/SecurityServiceImpl.java @@ -0,0 +1,39 @@ +package com.baeldung.mongoauth.service; + +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.stereotype.Service; + +@Service +public class SecurityServiceImpl implements SecurityService { + + private final AuthenticationManager authenticationManager; + + private final UserDetailsService userDetailsService; + + public SecurityServiceImpl(AuthenticationManager authenticationManager, UserDetailsService userDetailsService) { + this.authenticationManager = authenticationManager; + this.userDetailsService = userDetailsService; + } + + @Override + public boolean login(String username, String password) { + UserDetails userDetails = userDetailsService.loadUserByUsername(username); + + UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(userDetails, password, userDetails.getAuthorities()); + + authenticationManager.authenticate(usernamePasswordAuthenticationToken); + + if (usernamePasswordAuthenticationToken.isAuthenticated()) { + SecurityContextHolder.getContext() + .setAuthentication(usernamePasswordAuthenticationToken); + + return true; + } + + return false; + } +} diff --git a/spring-security-modules/spring-security-web-boot-3/src/main/resources/application.properties b/spring-security-modules/spring-security-web-boot-3/src/main/resources/application.properties new file mode 100644 index 0000000000..a5b5fb9804 --- /dev/null +++ b/spring-security-modules/spring-security-web-boot-3/src/main/resources/application.properties @@ -0,0 +1 @@ +spring.mongodb.embedded.version=4.4.9 \ No newline at end of file diff --git a/spring-security-modules/spring-security-web-boot-3/src/test/java/com/baeldung/mongoauth/MongoAuthApplicationIntegrationTest.java b/spring-security-modules/spring-security-web-boot-3/src/test/java/com/baeldung/mongoauth/MongoAuthApplicationIntegrationTest.java new file mode 100644 index 0000000000..b7994cad9e --- /dev/null +++ b/spring-security-modules/spring-security-web-boot-3/src/test/java/com/baeldung/mongoauth/MongoAuthApplicationIntegrationTest.java @@ -0,0 +1,118 @@ +package com.baeldung.mongoauth; + +import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.httpBasic; +import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import java.util.Collections; +import java.util.HashSet; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +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.data.mongodb.core.MongoTemplate; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.context.WebApplicationContext; + +import com.baeldung.mongoauth.domain.Role; +import com.baeldung.mongoauth.domain.User; +import com.baeldung.mongoauth.domain.UserRole; + +@SpringBootTest(classes = { MongoAuthApplication.class }) +@AutoConfigureMockMvc +@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD) +class MongoAuthApplicationIntegrationTest { + + @Autowired + private WebApplicationContext context; + + @Autowired + private MongoTemplate mongoTemplate; + + @Autowired + private BCryptPasswordEncoder bCryptPasswordEncoder; + + private MockMvc mvc; + + private static final String USER_NAME = "user@gmail.com"; + private static final String ADMIN_NAME = "admin@gmail.com"; + private static final String PASSWORD = "password"; + + @BeforeEach + public void setup() { + + setUp(); + + mvc = MockMvcBuilders.webAppContextSetup(context) + .apply(springSecurity()) + .build(); + } + + private void setUp() { + Role roleUser = new Role(); + roleUser.setName("ROLE_USER"); + mongoTemplate.save(roleUser); + + User user = new User(); + user.setUsername(USER_NAME); + user.setPassword(bCryptPasswordEncoder.encode(PASSWORD)); + + UserRole userRole = new UserRole(); + userRole.setRole(roleUser); + user.setUserRoles(new HashSet<>(Collections.singletonList(userRole))); + mongoTemplate.save(user); + + User admin = new User(); + admin.setUsername(ADMIN_NAME); + admin.setPassword(bCryptPasswordEncoder.encode(PASSWORD)); + + Role roleAdmin = new Role(); + roleAdmin.setName("ROLE_ADMIN"); + mongoTemplate.save(roleAdmin); + + UserRole adminRole = new UserRole(); + adminRole.setRole(roleAdmin); + admin.setUserRoles(new HashSet<>(Collections.singletonList(adminRole))); + mongoTemplate.save(admin); + } + + @Test + void givenUserCredentials_whenInvokeUserAuthorizedEndPoint_thenReturn200() throws Exception { + mvc.perform(get("/user").with(httpBasic(USER_NAME, PASSWORD))) + .andExpect(status().isOk()); + } + + @Test + void givenUserNotExists_whenInvokeEndPoint_thenReturn401() throws Exception { + mvc.perform(get("/user").with(httpBasic("not_existing_user", "password"))) + .andExpect(status().isUnauthorized()); + } + + @Test + void givenUserExistsAndWrongPassword_whenInvokeEndPoint_thenReturn401() throws Exception { + mvc.perform(get("/user").with(httpBasic(USER_NAME, "wrong_password"))) + .andExpect(status().isUnauthorized()); + } + + @Test + void givenUserCredentials_whenInvokeAdminAuthorizedEndPoint_thenReturn403() throws Exception { + mvc.perform(get("/admin").with(httpBasic(USER_NAME, PASSWORD))) + .andExpect(status().isForbidden()); + } + + @Test + void givenAdminCredentials_whenInvokeAdminAuthorizedEndPoint_thenReturn200() throws Exception { + mvc.perform(get("/admin").with(httpBasic(ADMIN_NAME, PASSWORD))) + .andExpect(status().isOk()); + + mvc.perform(get("/user").with(httpBasic(ADMIN_NAME, PASSWORD))) + .andExpect(status().isOk()); + } + +} diff --git a/spring-sleuth/pom.xml b/spring-sleuth/pom.xml index 5fd109e968..a6fba5ea56 100644 --- a/spring-sleuth/pom.xml +++ b/spring-sleuth/pom.xml @@ -39,7 +39,7 @@ - 2.0.2.RELEASE + 3.1.0 \ No newline at end of file diff --git a/spring-sleuth/src/main/java/com/baeldung/sleuth/traceid/SleuthCurrentTraceIdApp.java b/spring-sleuth/src/main/java/com/baeldung/sleuth/traceid/SleuthCurrentTraceIdApp.java new file mode 100644 index 0000000000..bae1d310a2 --- /dev/null +++ b/spring-sleuth/src/main/java/com/baeldung/sleuth/traceid/SleuthCurrentTraceIdApp.java @@ -0,0 +1,11 @@ +package com.baeldung.sleuth.traceid; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class SleuthCurrentTraceIdApp { + public static void main(String[] args) { + SpringApplication.run(SleuthCurrentTraceIdApp.class, args); + } +} diff --git a/spring-sleuth/src/main/java/com/baeldung/sleuth/traceid/SleuthTraceIdController.java b/spring-sleuth/src/main/java/com/baeldung/sleuth/traceid/SleuthTraceIdController.java new file mode 100644 index 0000000000..07dca487d0 --- /dev/null +++ b/spring-sleuth/src/main/java/com/baeldung/sleuth/traceid/SleuthTraceIdController.java @@ -0,0 +1,32 @@ +package com.baeldung.sleuth.traceid; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +import brave.Span; +import brave.Tracer; + +@RestController +public class SleuthTraceIdController { + + private static final Logger logger = LoggerFactory.getLogger(SleuthTraceIdController.class); + + @Autowired + private Tracer tracer; + + @GetMapping("/traceid") + public String getSleuthTraceId() { + logger.info("Hello with Sleuth"); + Span span = tracer.currentSpan(); + if (span != null) { + logger.info("Span ID hex {}", span.context().spanIdString()); + logger.info("Span ID decimal {}", span.context().spanId()); + logger.info("Trace ID hex {}", span.context().traceIdString()); + logger.info("Trace ID decimal {}", span.context().traceId()); + } + return "Hello from Sleuth"; + } +} diff --git a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateMachineIntegrationTest.java b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateMachineIntegrationTest.java index aab07225a3..5909340a82 100644 --- a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateMachineIntegrationTest.java +++ b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateMachineIntegrationTest.java @@ -3,6 +3,7 @@ package com.baeldung.spring.statemachine; import com.baeldung.spring.statemachine.config.SimpleStateMachineConfiguration; import org.junit.After; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; @@ -36,6 +37,7 @@ public class StateMachineIntegrationTest { assertEquals("S2", stateMachine.getState().getId()); } + @Ignore("Fixing in JAVA-9808") @Test public void whenSimpleStringMachineActionState_thenActionExecuted() { diff --git a/testing-modules/pom.xml b/testing-modules/pom.xml index 58ea74484e..3d5db76827 100644 --- a/testing-modules/pom.xml +++ b/testing-modules/pom.xml @@ -45,6 +45,7 @@ testing-libraries-2 testing-libraries testng + testng-command-line xmlunit-2 zerocode diff --git a/testing-modules/testng_command_line/README.md b/testing-modules/testng-command-line/README.md similarity index 100% rename from testing-modules/testng_command_line/README.md rename to testing-modules/testng-command-line/README.md diff --git a/testing-modules/testng_command_line/pom.xml b/testing-modules/testng-command-line/pom.xml similarity index 97% rename from testing-modules/testng_command_line/pom.xml rename to testing-modules/testng-command-line/pom.xml index 4c3af7621c..efc49b187d 100644 --- a/testing-modules/testng_command_line/pom.xml +++ b/testing-modules/testng-command-line/pom.xml @@ -3,10 +3,10 @@ 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"> 4.0.0 - - com.baeldung.testing_modules - testng_command_line + testng-command-line 1.0.0-SNAPSHOT + testng-command-line + com.baeldung testing-modules diff --git a/testing-modules/testng_command_line/src/main/java/com/baeldung/testing_modules/testng_command_line/DateSerializerService.java b/testing-modules/testng-command-line/src/main/java/com/baeldung/testng/DateSerializerService.java similarity index 82% rename from testing-modules/testng_command_line/src/main/java/com/baeldung/testing_modules/testng_command_line/DateSerializerService.java rename to testing-modules/testng-command-line/src/main/java/com/baeldung/testng/DateSerializerService.java index 2c4c1f3a4b..a9a7cc4ee6 100644 --- a/testing-modules/testng_command_line/src/main/java/com/baeldung/testing_modules/testng_command_line/DateSerializerService.java +++ b/testing-modules/testng-command-line/src/main/java/com/baeldung/testng/DateSerializerService.java @@ -1,4 +1,4 @@ -package com.baeldung.testing_modules.testng_command_line; +package com.baeldung.testng; import java.text.SimpleDateFormat; import java.util.Date; diff --git a/testing-modules/testng_command_line/src/test/java/com/baeldung/testing_modules/testng_command_line/DateSerializerServiceUnitTest.java b/testing-modules/testng-command-line/src/test/java/com/baeldung/testng/DateSerializerServiceUnitTest.java similarity index 87% rename from testing-modules/testng_command_line/src/test/java/com/baeldung/testing_modules/testng_command_line/DateSerializerServiceUnitTest.java rename to testing-modules/testng-command-line/src/test/java/com/baeldung/testng/DateSerializerServiceUnitTest.java index 4deb0297f0..2b9a9a0925 100644 --- a/testing-modules/testng_command_line/src/test/java/com/baeldung/testing_modules/testng_command_line/DateSerializerServiceUnitTest.java +++ b/testing-modules/testng-command-line/src/test/java/com/baeldung/testng/DateSerializerServiceUnitTest.java @@ -1,7 +1,8 @@ -package com.baeldung.testing_modules.testng_command_line; +package com.baeldung.testng; import java.util.Date; +import com.baeldung.testng.DateSerializerService; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; diff --git a/testing-modules/testng_command_line/testng.xml b/testing-modules/testng-command-line/testng.xml similarity index 67% rename from testing-modules/testng_command_line/testng.xml rename to testing-modules/testng-command-line/testng.xml index eca48a6d39..4e029f9dc6 100644 --- a/testing-modules/testng_command_line/testng.xml +++ b/testing-modules/testng-command-line/testng.xml @@ -4,7 +4,7 @@ + name="com.baeldung.testng.DateSerializerServiceUnitTest" />