diff --git a/java-17/pom.xml b/java-18/pom.xml
similarity index 70%
rename from java-17/pom.xml
rename to java-18/pom.xml
index 0c1c6e0..9f4a0ed 100644
--- a/java-17/pom.xml
+++ b/java-18/pom.xml
@@ -4,32 +4,32 @@
http://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0
com.mkyong
- java17
+ java18
1.0
- java-17
- https://www.mkyong.com
+ java-18
+ https://mkyong.com
UTF-8
- 17
- 17
- 17
+ 18
+ 18
+ 18
- java17
+ java18
org.apache.maven.plugins
maven-compiler-plugin
3.8.1
- 17
- 17
+ 18
+ 18
--enable-preview
diff --git a/java-18/src/main/java/com/mkyong/java18/jep418/JEP418.java b/java-18/src/main/java/com/mkyong/java18/jep418/JEP418.java
new file mode 100644
index 0000000..cc9173d
--- /dev/null
+++ b/java-18/src/main/java/com/mkyong/java18/jep418/JEP418.java
@@ -0,0 +1,23 @@
+package com.mkyong.java18.jep418;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.net.spi.InetAddressResolver;
+import java.net.spi.InetAddressResolverProvider;
+
+public class JEP418 {
+
+ public static void main(String[] args) throws UnknownHostException {
+
+ // Returns a set of ip address, ipv4 and ipv6.
+ InetAddress[] machines = InetAddress.getAllByName("google.com");
+ for (InetAddress address : machines) {
+ System.out.println(address.getHostAddress());
+ }
+
+ // Returns first address in its set of addresses.
+ InetAddress ip = InetAddress.getByName("google.com");
+ System.out.println(ip.getHostAddress());
+
+ }
+}
diff --git a/java-18/src/main/java/com/mkyong/java18/jep420/JEP420.java b/java-18/src/main/java/com/mkyong/java18/jep420/JEP420.java
new file mode 100644
index 0000000..a3604a1
--- /dev/null
+++ b/java-18/src/main/java/com/mkyong/java18/jep420/JEP420.java
@@ -0,0 +1,21 @@
+package com.mkyong.java18.jep420;
+
+public class JEP420 {
+
+ public static void main(String[] args) {
+
+ }
+
+ // java: this case label is dominated by a preceding case label
+ /*static void error (Object o){
+ switch (o) {
+ case CharSequence cs -> System.out.println("A sequence of length " + cs.length());
+ case String s -> // Error - pattern is dominated by previous pattern
+ System.out.println("A string: " + s);
+ default -> {
+ break;
+ }
+ }
+ }*/
+
+}
diff --git a/java-18/src/main/java/com/mkyong/java18/jep420/JEP420_2.java b/java-18/src/main/java/com/mkyong/java18/jep420/JEP420_2.java
new file mode 100644
index 0000000..67095ac
--- /dev/null
+++ b/java-18/src/main/java/com/mkyong/java18/jep420/JEP420_2.java
@@ -0,0 +1,25 @@
+package com.mkyong.java18.jep420;
+
+public class JEP420_2 {
+
+ // java: the switch expression does not cover all possible input values
+ // error
+ /*static int coverage(Object o) {
+ return switch (o) { // Error - not exhaustive
+ case String s -> s.length();
+ case Integer i -> i;
+ };
+ }*/
+
+ static int coverage(Object o) {
+ return switch (o) {
+ case String s -> s.length();
+ case Integer i -> i;
+ default -> 0;
+ };
+ }
+
+ public static void main(String[] args) {
+ System.out.println("Hello JEP 420");
+ }
+}
diff --git a/java-18/src/main/java/com/mkyong/java18/jep421/JEP421.java b/java-18/src/main/java/com/mkyong/java18/jep421/JEP421.java
new file mode 100644
index 0000000..ddc1ca3
--- /dev/null
+++ b/java-18/src/main/java/com/mkyong/java18/jep421/JEP421.java
@@ -0,0 +1,43 @@
+package com.mkyong.java18.jep421;
+
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+public class JEP421 {
+
+ public static void main(String[] args) throws IOException {
+
+ String file1 = "/Home/mkyong/file1";
+ String file2 = "/Home/mkyong/file1";
+
+ FileInputStream input = null;
+ FileOutputStream output = null;
+ try {
+ input = new FileInputStream(file1);
+ output = new FileOutputStream(file2);
+
+ // copy files from file1 to file 2
+
+ output.close();
+ output = null;
+ input.close();
+ input = null;
+ } finally {
+ if (output != null) output.close();
+ if (input != null) input.close();
+ }
+
+ /*try (FileInputStream input = new FileInputStream(file1);
+ FileOutputStream output = new FileOutputStream(file2)) {
+ //
+ }*/
+
+
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ super.finalize();
+ }
+}
diff --git a/java-19/pom.xml b/java-19/pom.xml
new file mode 100644
index 0000000..3f2c5ce
--- /dev/null
+++ b/java-19/pom.xml
@@ -0,0 +1,38 @@
+
+ 4.0.0
+ com.mkyong
+ java19
+ 1.0
+
+ java-19
+ https://mkyong.com
+
+
+ UTF-8
+ 19
+ 19
+ 19
+
+
+
+
+
+
+ java19
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.8.1
+
+ 19
+ 19
+ --enable-preview
+
+
+
+
+
diff --git a/java-19/src/main/java/com/mkyong/java19/jep405/JEP405.java b/java-19/src/main/java/com/mkyong/java19/jep405/JEP405.java
new file mode 100644
index 0000000..edc2b29
--- /dev/null
+++ b/java-19/src/main/java/com/mkyong/java19/jep405/JEP405.java
@@ -0,0 +1,25 @@
+package com.mkyong.java19.jep405;
+
+public class JEP405 {
+
+ record Point(int x, int y) {
+ }
+
+ static void printSum(Object o) {
+ if (o instanceof Point p) {
+ int x = p.x(); // get x()
+ int y = p.y(); // get y()
+ System.out.println(x + y);
+ }
+ }
+
+ static void printSumNew(Object o) {
+ if (o instanceof Point(int x,int y)) { // record pattern
+ System.out.println(x + y);
+ }
+ }
+
+ public static void main(String[] args) {
+ printSumNew(new Point(10, 20)); // output 30
+ }
+}
\ No newline at end of file
diff --git a/java-19/src/main/java/com/mkyong/java19/jep405/JEP405_1.java b/java-19/src/main/java/com/mkyong/java19/jep405/JEP405_1.java
new file mode 100644
index 0000000..558ba90
--- /dev/null
+++ b/java-19/src/main/java/com/mkyong/java19/jep405/JEP405_1.java
@@ -0,0 +1,23 @@
+package com.mkyong.java19.jep405;
+
+public class JEP405_1 {
+
+ record Point(int x, int y) {
+ }
+
+ record Total(Point p1, Point p2) {
+ }
+
+ static void printSum(Object o) {
+ // record nested pattern
+ if (o instanceof Total(Point(int x,int y),Point(int x2,int y2))) {
+ System.out.println(x + y + x2 + y2);
+ }
+ }
+
+ public static void main(String[] args) {
+
+ printSum(new Total(new Point(10, 5), new Point(2, 3)));
+
+ }
+}
diff --git a/java-19/src/main/java/com/mkyong/java19/jep424/JEP424_SORT.java b/java-19/src/main/java/com/mkyong/java19/jep424/JEP424_SORT.java
new file mode 100644
index 0000000..56bf31c
--- /dev/null
+++ b/java-19/src/main/java/com/mkyong/java19/jep424/JEP424_SORT.java
@@ -0,0 +1,57 @@
+package com.mkyong.java19.jep424;
+
+import java.lang.foreign.FunctionDescriptor;
+import java.lang.foreign.Linker;
+import java.lang.foreign.MemoryAddress;
+import java.lang.foreign.MemorySegment;
+import java.lang.foreign.SegmentAllocator;
+import java.lang.foreign.SymbolLookup;
+import java.lang.foreign.ValueLayout;
+import java.lang.invoke.MethodHandle;
+
+import static java.lang.foreign.ValueLayout.*;
+
+public class JEP424_SORT {
+
+ public static void main(String[] args) throws Throwable {
+
+ // 1. Find foreign function on the C library path
+ Linker linker = Linker.nativeLinker();
+ SymbolLookup stdlib = linker.defaultLookup();
+
+ // 2. Allocate on-heap memory to store strings
+ String[] javaStrings = {"d", "z", "b", "c", "a"};
+
+ // 3. Allocate off-heap memory to store pointers
+ SegmentAllocator allocator = SegmentAllocator.implicitAllocator();
+ MemorySegment offHeap = allocator.allocateArray(ValueLayout.ADDRESS, javaStrings.length);
+
+ // 4. Copy the strings from on-heap to off-heap
+ for (int i = 0; i < javaStrings.length; i++) {
+
+ // Allocate a string off-heap, then store a pointer to it
+ MemorySegment cString = allocator.allocateUtf8String(javaStrings[i]);
+ offHeap.setAtIndex(ValueLayout.ADDRESS, i, cString);
+ }
+
+ MethodHandle radixSort = linker.downcallHandle(
+ stdlib.lookup("radixsort").orElseThrow(),
+ FunctionDescriptor.ofVoid(ADDRESS, JAVA_INT, ADDRESS, JAVA_CHAR));
+
+ // 5. Sort the off-heap data by calling the foreign function
+ radixSort.invoke(offHeap, javaStrings.length, MemoryAddress.NULL, '\0');
+
+ // 6. Copy the (reordered) strings from off-heap to on-heap
+ for (int i = 0; i < javaStrings.length; i++) {
+ MemoryAddress cStringPtr = offHeap.getAtIndex(ValueLayout.ADDRESS, i);
+ javaStrings[i] = cStringPtr.getUtf8String(0);
+ }
+
+ //print sort result
+ for (String javaString : javaStrings) {
+ System.out.println(javaString);
+ }
+
+ }
+
+}
diff --git a/java-19/src/main/java/com/mkyong/java19/jep424/JEP424_STRLEN.java b/java-19/src/main/java/com/mkyong/java19/jep424/JEP424_STRLEN.java
new file mode 100644
index 0000000..652638d
--- /dev/null
+++ b/java-19/src/main/java/com/mkyong/java19/jep424/JEP424_STRLEN.java
@@ -0,0 +1,34 @@
+package com.mkyong.java19.jep424;
+
+import java.lang.foreign.*;
+import java.lang.invoke.MethodHandle;
+
+import static java.lang.foreign.ValueLayout.ADDRESS;
+import static java.lang.foreign.ValueLayout.JAVA_LONG;
+
+public class JEP424_STRLEN {
+
+ public static void main(String[] args) throws Throwable {
+
+ String input = "Hello World";
+
+ // 1. Find foreign function on the C library path
+ SymbolLookup stdlib = Linker.nativeLinker().defaultLookup();
+
+ // 2. Get a handle to the "strlen" function in the C standard library
+ MethodHandle methodHandle = Linker.nativeLinker().downcallHandle(
+ stdlib.lookup("strlen").orElseThrow(),
+ FunctionDescriptor.of(JAVA_LONG, ADDRESS));
+
+ // 3. Allocate off-heap memory to store strings
+ MemorySegment memorySegment = SegmentAllocator
+ .implicitAllocator().allocateUtf8String(input);
+
+ // 4. Runs the foreign function "strlen"
+ long length = (long) methodHandle.invoke(memorySegment);
+
+ System.out.println("length = " + length);
+
+ }
+
+}
diff --git a/java-19/src/main/java/com/mkyong/java19/jep425/JEP425.java b/java-19/src/main/java/com/mkyong/java19/jep425/JEP425.java
new file mode 100644
index 0000000..070cc20
--- /dev/null
+++ b/java-19/src/main/java/com/mkyong/java19/jep425/JEP425.java
@@ -0,0 +1,32 @@
+package com.mkyong.java19.jep425;
+
+import java.time.Duration;
+import java.util.concurrent.Executors;
+import java.util.stream.IntStream;
+
+public class JEP425 {
+
+ public static void main(String[] args) {
+
+ try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
+ IntStream.range(0, 10_000).forEach(i -> {
+ executor.submit(() -> {
+ Thread.sleep(Duration.ofSeconds(1));
+ return i;
+ });
+ });
+ } // executor.close() is called implicitly, and waits
+
+ /*try (var executor = Executors.newFixedThreadPool(20)) {
+ IntStream.range(0, 10_000).forEach(i -> {
+ executor.submit(() -> {
+ Thread.sleep(Duration.ofSeconds(1));
+ return i;
+ });
+ });
+ }*/
+
+ System.out.println("Done");
+
+ }
+}
diff --git a/java-19/src/main/java/com/mkyong/java19/jep427/JEP427.java b/java-19/src/main/java/com/mkyong/java19/jep427/JEP427.java
new file mode 100644
index 0000000..9d6724a
--- /dev/null
+++ b/java-19/src/main/java/com/mkyong/java19/jep427/JEP427.java
@@ -0,0 +1,31 @@
+package com.mkyong.java19.jep427;
+
+public class JEP427 {
+
+ public static void main(String[] args) {
+
+ testJava19("mkyong");
+ testJava19("mkyongmkyong");
+ }
+
+ /* Old guarded pattern
+ static void test(Object o) {
+ switch (o) {
+ case String s && s.length() > 6 -> System.out.println("String's length longer than 10!");
+ case String s -> System.out.println("String's length is " + s.length());
+ default -> {
+ }
+ }
+ }*/
+
+ //Guarded patterns are replaced with when clauses in switch blocks.
+ static void testJava19(Object o) {
+ switch (o) {
+ case String s
+ when s.length() > 10 -> System.out.println("String's length longer than 10!");
+ case String s -> System.out.println("String's length is " + s.length());
+ default -> {}
+ }
+ }
+
+}
diff --git a/java-19/src/main/java/com/mkyong/java19/jep428/JEP428.java b/java-19/src/main/java/com/mkyong/java19/jep428/JEP428.java
new file mode 100644
index 0000000..7f771f2
--- /dev/null
+++ b/java-19/src/main/java/com/mkyong/java19/jep428/JEP428.java
@@ -0,0 +1,50 @@
+package com.mkyong.java19.jep428;
+
+import java.time.Duration;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+
+public class JEP428 {
+
+ public static void main(String[] args) throws ExecutionException, InterruptedException {
+ JEP428 obj = new JEP428();
+ obj.handleUnStructureAPI();
+ }
+
+ Response handleUnStructureAPI() throws ExecutionException, InterruptedException {
+ try (var executor = Executors.newFixedThreadPool(10)) {
+ Future user = executor.submit(this::findUser);
+ Future order = executor.submit(this::fetchOrder);
+ String theUser = user.get(); // Join findUser
+ int theOrder = order.get(); // Join fetchOrder
+ return new Response(theUser, theOrder);
+ }
+ }
+
+ /*Response handleStructureAPI() throws ExecutionException, InterruptedException {
+ try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
+ Future user = scope.fork(this::findUser);
+ Future order = scope.fork(this::fetchOrder);
+
+ scope.join(); // Join both forks
+ scope.throwIfFailed(); // ... and propagate errors
+
+ // Here, both forks have succeeded, so compose their results
+ return new Response(user.resultNow(), order.resultNow());
+ }
+ }*/
+
+ private String findUser() throws InterruptedException {
+ Thread.sleep(Duration.ofSeconds(1));
+ return "mkyong";
+ }
+
+ private Integer fetchOrder() throws InterruptedException {
+ Thread.sleep(Duration.ofSeconds(1));
+ return 1;
+ }
+
+ record Response(String x, int y) {
+ }
+}
diff --git a/java-basic/pom.xml b/java-basic/pom.xml
index 1fd652e..224019c 100644
--- a/java-basic/pom.xml
+++ b/java-basic/pom.xml
@@ -14,9 +14,9 @@
UTF-8
- 11
- 11
- 11
+ 17
+ 17
+ 17
5.4.0
@@ -35,6 +35,20 @@
test
+
+
+
+ com.sun.activation
+ jakarta.activation
+ 2.0.1
+
+
diff --git a/java-io/pom.xml b/java-io/pom.xml
index f2ca168..cbf8ea1 100644
--- a/java-io/pom.xml
+++ b/java-io/pom.xml
@@ -16,7 +16,7 @@
UTF-8
17
17
- 17
+ 21
5.4.0
diff --git a/java-io/src/main/java/com/mkyong/io/howto/FileTraverseExample.java b/java-io/src/main/java/com/mkyong/io/howto/FileTraverseExample.java
new file mode 100644
index 0000000..3d23fb5
--- /dev/null
+++ b/java-io/src/main/java/com/mkyong/io/howto/FileTraverseExample.java
@@ -0,0 +1,28 @@
+package com.mkyong.io.howto;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.stream.Stream;
+
+public class FileTraverseExample {
+
+ public static void main(String[] args) {
+
+ // Specify the directory we want to traverse
+ String dirPath = "/Users/yongmookkim/projects/test/";
+
+ // Traverse the directory and process files
+ try (Stream paths = Files.walk(Paths.get(dirPath))) {
+
+ paths
+ .filter(Files::isRegularFile) // ensure it is a file
+ .forEach(System.out::println); // prints the file path
+
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+
+ }
+}
diff --git a/java-io/src/main/java/com/mkyong/io/howto/FileTraverseExample2.java b/java-io/src/main/java/com/mkyong/io/howto/FileTraverseExample2.java
new file mode 100644
index 0000000..e9a6a83
--- /dev/null
+++ b/java-io/src/main/java/com/mkyong/io/howto/FileTraverseExample2.java
@@ -0,0 +1,38 @@
+package com.mkyong.io.howto;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.List;
+import java.util.stream.Stream;
+
+public class FileTraverseExample2 {
+
+ public static void main(String[] args) {
+
+ List result;
+
+ // Specify the directory we want to traverse
+ String dirPath = "/Users/yongmookkim/projects/test/";
+
+ // Traverse the directory and process files
+ try (Stream paths = Files.walk(Paths.get(dirPath))) {
+
+ result = paths
+ .filter(Files::isRegularFile) // ensure it is a file
+ .map(p -> p.getFileName().toString())
+ .toList();
+
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+
+ System.out.println("Total files: " + result.size());
+ for (String name : result) {
+ System.out.println("FileName: " + name);
+ }
+
+
+ }
+}
diff --git a/java-io/src/main/java/com/mkyong/io/howto/FileTraverseExample3.java b/java-io/src/main/java/com/mkyong/io/howto/FileTraverseExample3.java
new file mode 100644
index 0000000..1d5c4e7
--- /dev/null
+++ b/java-io/src/main/java/com/mkyong/io/howto/FileTraverseExample3.java
@@ -0,0 +1,40 @@
+package com.mkyong.io.howto;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Optional;
+import java.util.stream.Stream;
+
+public class FileTraverseExample3 {
+
+ public static void main(String[] args) {
+
+ String dir = "/Users/yongmookkim/projects/test/";
+ String findThisFile = "a.txt";
+
+ try {
+
+ Optional foundFile = findFileByName(Paths.get(dir), findThisFile);
+ foundFile.ifPresentOrElse(
+ file -> System.out.println("File found: " + file),
+ () -> System.out.println("File not found.")
+ );
+
+ } catch (IOException e) {
+ System.err.println("An error occurred while searching for the file: " + e.getMessage());
+ }
+
+ }
+
+ public static Optional findFileByName(Path directory, String fileName) throws IOException {
+ try (Stream stream = Files.walk(directory)) {
+ return stream
+ .filter(Files::isRegularFile)
+ .filter(path -> path.getFileName().toString().equals(fileName))
+ .findFirst();
+ }
+ }
+
+}
diff --git a/java-string/pom.xml b/java-string/pom.xml
new file mode 100644
index 0000000..150bf01
--- /dev/null
+++ b/java-string/pom.xml
@@ -0,0 +1,66 @@
+
+
+
+ 4.0.0
+ com.mkyong
+ string
+ 1.0
+
+ java-string
+ https://mkyong.com
+
+
+ UTF-8
+ 17
+ 17
+ 17
+ 5.8.2
+ 3.12.0
+ 1.9
+
+
+
+
+
+ org.junit.jupiter
+ junit-jupiter-params
+ ${junit5.version}
+ test
+
+
+
+
+
+ org.apache.commons
+ commons-lang3
+ ${commons-lang3.version}
+
+
+
+
+
+ org.apache.commons
+ commons-text
+ ${commons-text.version}
+
+
+
+
+
+ java-basic
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.8.1
+
+ ${java.version}
+ ${java.version}
+
+
+
+
+
diff --git a/java-string/src/main/java/com/mkyong/string/ConvertBytesToString.java b/java-string/src/main/java/com/mkyong/string/ConvertBytesToString.java
new file mode 100644
index 0000000..d3c5506
--- /dev/null
+++ b/java-string/src/main/java/com/mkyong/string/ConvertBytesToString.java
@@ -0,0 +1,20 @@
+package com.mkyong.string;
+
+import java.nio.charset.StandardCharsets;
+
+public class ConvertBytesToString {
+
+ public static void main(String[] args) {
+
+ // String to byte[]
+ byte[] bytes = "mkyong".getBytes(StandardCharsets.UTF_8);
+
+ // byte[] to String
+ String s = new String(bytes, StandardCharsets.UTF_8);
+
+ // mkyong
+ System.out.println(s);
+
+ }
+
+}
\ No newline at end of file
diff --git a/java-string/src/main/java/com/mkyong/string/ConvertBytesToString2.java b/java-string/src/main/java/com/mkyong/string/ConvertBytesToString2.java
new file mode 100644
index 0000000..1a04dce
--- /dev/null
+++ b/java-string/src/main/java/com/mkyong/string/ConvertBytesToString2.java
@@ -0,0 +1,29 @@
+package com.mkyong.string;
+
+import java.nio.charset.StandardCharsets;
+
+public class ConvertBytesToString2 {
+
+ public static void main(String[] args) {
+
+ String str = "This is raw text!";
+
+ // string to byte[]
+ byte[] bytes = str.getBytes(StandardCharsets.UTF_8);
+
+ System.out.println("Text : " + str);
+ System.out.println("Text [Byte Format] : " + bytes);
+
+ // no, don't do this, it returns the address of the object in memory
+ System.out.println("Text [Byte Format] toString() : " + bytes.toString());
+
+ // convert byte[] to string
+ String s = new String(bytes, StandardCharsets.UTF_8);
+ System.out.println("Output : " + s);
+
+ // old code, UnsupportedEncodingException
+ // String s1 = new String(bytes, "UTF_8");
+
+ }
+
+}
\ No newline at end of file
diff --git a/java-string/src/main/java/com/mkyong/string/ConvertBytesToStringBase64.java b/java-string/src/main/java/com/mkyong/string/ConvertBytesToStringBase64.java
new file mode 100644
index 0000000..ae578aa
--- /dev/null
+++ b/java-string/src/main/java/com/mkyong/string/ConvertBytesToStringBase64.java
@@ -0,0 +1,41 @@
+package com.mkyong.string;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Base64;
+
+public class ConvertBytesToStringBase64 {
+
+ public static void main(String[] args) {
+
+ String filepath = "/Users/mkyong/phone.png";
+ Path path = Paths.get(filepath);
+
+ if (Files.notExists(path)) {
+ throw new IllegalArgumentException("File is not exists!");
+ }
+
+ try {
+
+ // convert the file's content to byte[]
+ byte[] bytes = Files.readAllBytes(path);
+
+ // encode, byte[] to Base64 encoded string
+ String s = Base64.getEncoder().encodeToString(bytes);
+ System.out.println(s);
+
+ // decode, Base64 encoded string to byte[]
+ byte[] decode = Base64.getDecoder().decode(s);
+
+ // save into another image file.
+ Files.write(Paths.get("/Users/mkyong/phone2.png"), decode);
+
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/java-string/src/main/java/com/mkyong/string/ConvertInputStreamToString.java b/java-string/src/main/java/com/mkyong/string/ConvertInputStreamToString.java
new file mode 100644
index 0000000..28db45b
--- /dev/null
+++ b/java-string/src/main/java/com/mkyong/string/ConvertInputStreamToString.java
@@ -0,0 +1,106 @@
+package com.mkyong.string;
+
+import java.io.*;
+import java.net.URI;
+import java.nio.charset.StandardCharsets;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+public class ConvertInputStreamToString {
+
+ public static final int DEFAULT_BUFFER_SIZE = 8192;
+
+ public static void main(String[] args) throws IOException {
+
+ URI uri = URI.create("https://www.google.com/");
+ try (InputStream inputStream = uri.toURL().openStream()) {
+
+ // Convert InputStream -> String
+ String result = convertInputStreamToString4(inputStream);
+
+ System.out.println(result);
+
+ }
+
+ }
+
+ // Plain Java
+ private static String convertInputStreamToString(InputStream is) throws IOException {
+
+ ByteArrayOutputStream result = new ByteArrayOutputStream();
+ byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
+ int length;
+ while ((length = is.read(buffer)) != -1) {
+ result.write(buffer, 0, length);
+ }
+
+ // Java 1.1
+ //return result.toString(StandardCharsets.UTF_8.name());
+
+ return result.toString("UTF-8");
+
+ // Java 10
+ //return result.toString(StandardCharsets.UTF_8);
+
+ }
+
+ // @Java 9 -> inputStream.readAllBytes()
+ // max bytes Integer.MAX_VALUE, 2147483647, which is 2G
+ private static String convertInputStreamToStringJava9(InputStream inputStream)
+ throws IOException {
+
+ return new String(inputStream.readAllBytes(), StandardCharsets.UTF_8);
+ }
+
+ // InputStreamReader + StringBuilder
+ private static String convertInputStreamToString2(InputStream inputStream)
+ throws IOException {
+
+ final char[] buffer = new char[8192];
+ final StringBuilder result = new StringBuilder();
+
+ // InputStream -> Reader
+ try (Reader reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8)) {
+ int charsRead;
+ while ((charsRead = reader.read(buffer, 0, buffer.length)) > 0) {
+ result.append(buffer, 0, charsRead);
+ }
+ }
+
+ return result.toString();
+
+ }
+
+ // InputStreamReader + BufferedReader (modify line breaks)
+ private static String convertInputStreamToString3(InputStream inputStream)
+ throws IOException {
+
+ String newLine = System.getProperty("line.separator");
+ StringBuilder result = new StringBuilder();
+ try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
+ String line;
+ while ((line = reader.readLine()) != null) {
+ result
+ .append(line)
+ .append(newLine);
+ }
+ }
+ return result.toString();
+
+ }
+
+ // Java 8 BufferedReader#lines (modify line breaks)
+ private static String convertInputStreamToString4(InputStream inputStream)
+ throws IOException {
+
+ String newLine = System.getProperty("line.separator");
+ String result;
+ try (Stream lines = new BufferedReader(new InputStreamReader(inputStream)).lines()) {
+ result = lines.collect(Collectors.joining(newLine));
+ }
+
+ return result;
+
+ }
+
+}
\ No newline at end of file
diff --git a/java-string/src/main/java/com/mkyong/string/ConvertStringToBytes.java b/java-string/src/main/java/com/mkyong/string/ConvertStringToBytes.java
new file mode 100644
index 0000000..082c720
--- /dev/null
+++ b/java-string/src/main/java/com/mkyong/string/ConvertStringToBytes.java
@@ -0,0 +1,31 @@
+package com.mkyong.string;
+
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.util.Base64;
+
+public class ConvertStringToBytes {
+
+ public static void main(String[] args) {
+
+ String example = "This is an example";
+
+ // default charset, a bit dangerous
+ byte[] output1 = example.getBytes();
+
+ // in old days, before java 1.7
+ byte[] output2 = example.getBytes(Charset.forName("UTF-8"));
+
+ // the best , java 1.7+
+ byte[] output3 = example.getBytes(StandardCharsets.UTF_8);
+
+ System.out.println("Text : " + example);
+
+ // base64 encode
+ String base64encoded = Base64.getEncoder().encodeToString(output3);
+
+ System.out.println("Text [Base64] : " + base64encoded);
+
+ }
+
+}
diff --git a/java-string/src/main/java/com/mkyong/string/ConvertStringToInputStream.java b/java-string/src/main/java/com/mkyong/string/ConvertStringToInputStream.java
new file mode 100644
index 0000000..4b61573
--- /dev/null
+++ b/java-string/src/main/java/com/mkyong/string/ConvertStringToInputStream.java
@@ -0,0 +1,37 @@
+package com.mkyong.string;
+
+import java.io.*;
+import java.nio.charset.StandardCharsets;
+
+public class ConvertStringToInputStream {
+
+ public static final int DEFAULT_BUFFER_SIZE = 8192;
+
+ public static void main(String[] args) throws IOException {
+
+ String name = "mkyong.com";
+
+ // String to InputStream
+ InputStream is = new ByteArrayInputStream(name.getBytes(StandardCharsets.UTF_8));
+
+ save(is, "c:\\test\\file.txt");
+
+ }
+
+ // save the InputStream to a File
+ private static void save(final InputStream is, final String fileName)
+ throws IOException {
+
+ // read bytes from InputStream and write it to FileOutputStream
+ try (FileOutputStream outputStream =
+ new FileOutputStream(new File(fileName), false)) {
+ int read;
+ byte[] bytes = new byte[DEFAULT_BUFFER_SIZE];
+ while ((read = is.read(bytes)) != -1) {
+ outputStream.write(bytes, 0, read);
+ }
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/java-string/src/main/java/com/mkyong/string/ConvertStringToInt.java b/java-string/src/main/java/com/mkyong/string/ConvertStringToInt.java
new file mode 100644
index 0000000..8a2c7ed
--- /dev/null
+++ b/java-string/src/main/java/com/mkyong/string/ConvertStringToInt.java
@@ -0,0 +1,26 @@
+package com.mkyong.string;
+
+public class ConvertStringToInt {
+
+ public static void main(String[] args) {
+
+ /*String number = "1";
+
+ // String to int
+ int result = Integer.parseInt(number);
+
+ // 1
+ System.out.println(result);*/
+
+ String number = "1A";
+ try {
+ int result = Integer.parseInt(number);
+ System.out.println(result);
+ } catch (NumberFormatException e) {
+ //do something for the exception.
+ System.err.println("Invalid number format : " + number);
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/java-string/src/main/java/com/mkyong/string/ConvertStringToInt2.java b/java-string/src/main/java/com/mkyong/string/ConvertStringToInt2.java
new file mode 100644
index 0000000..c73c7a3
--- /dev/null
+++ b/java-string/src/main/java/com/mkyong/string/ConvertStringToInt2.java
@@ -0,0 +1,21 @@
+package com.mkyong.string;
+
+public class ConvertStringToInt2 {
+
+ public static void main(String[] args) {
+
+ // 2147483647
+ System.out.println(Integer.MAX_VALUE);
+
+ String number = "2147483648";
+ try {
+ int result = Integer.parseInt(number);
+ System.out.println(result);
+ } catch (NumberFormatException e) {
+ //do something for the exception.
+ System.err.println("Invalid number format : " + number);
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/java-string/src/main/java/com/mkyong/string/ConvertStringToInteger.java b/java-string/src/main/java/com/mkyong/string/ConvertStringToInteger.java
new file mode 100644
index 0000000..982bd86
--- /dev/null
+++ b/java-string/src/main/java/com/mkyong/string/ConvertStringToInteger.java
@@ -0,0 +1,26 @@
+package com.mkyong.string;
+
+public class ConvertStringToInteger {
+
+ public static void main(String[] args) {
+
+ /*String number = "99";
+
+ // String to integer
+ Integer result = Integer.valueOf(number);
+
+ // 99
+ System.out.println(result);*/
+
+ String number = "D99";
+ try {
+ Integer result = Integer.valueOf(number);
+ System.out.println(result);
+ } catch (NumberFormatException e) {
+ //do something for the exception.
+ System.err.println("Invalid number format : " + number);
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/java-string/src/main/java/com/mkyong/string/ConvertStringToIntegerJava8.java b/java-string/src/main/java/com/mkyong/string/ConvertStringToIntegerJava8.java
new file mode 100644
index 0000000..da8c298
--- /dev/null
+++ b/java-string/src/main/java/com/mkyong/string/ConvertStringToIntegerJava8.java
@@ -0,0 +1,37 @@
+package com.mkyong.string;
+
+import java.util.Optional;
+
+public class ConvertStringToIntegerJava8 {
+
+ public static void main(String[] args) {
+
+ String number = "99";
+
+ Optional result = convertStringToInteger(number);
+
+ if (result.isPresent()) {
+ System.out.println(result.get());
+ } else {
+ System.err.println("Unable to convert the number : " + number);
+ }
+
+ }
+
+ private static Optional convertStringToInteger(String input) {
+
+ if (input == null) return Optional.empty();
+
+ input = input.trim();
+
+ if (input.isEmpty()) return Optional.empty();
+
+ try {
+ return Optional.of(Integer.valueOf(input));
+ } catch (NumberFormatException e) {
+ return Optional.empty();
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/java-string/src/main/java/com/mkyong/string/StringTokenizerExample.java b/java-string/src/main/java/com/mkyong/string/StringTokenizerExample.java
new file mode 100644
index 0000000..ce53c08
--- /dev/null
+++ b/java-string/src/main/java/com/mkyong/string/StringTokenizerExample.java
@@ -0,0 +1,83 @@
+package com.mkyong.string;
+
+import java.io.BufferedReader;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.StringTokenizer;
+
+public class StringTokenizerExample {
+
+ public static void main(String[] args) throws IOException {
+
+ StringTokenizer st = new StringTokenizer("1, 2, 3, 4, 5");
+ while (st.hasMoreTokens()) {
+ System.out.println(st.nextToken().trim());
+ }
+
+ /*String line = "This is a String, split by, StringTokenizer example.";
+ List result = split(line, ",");
+ for (String s : result) {
+ System.out.println(s.trim());
+ }*/
+
+ /*StringTokenizerExample obj = new StringTokenizerExample();
+ List trends = obj.readFile(Paths.get("C:\\test\\sample.csv"), "|");
+ trends.forEach(System.out::println);*/
+ }
+
+ public static List split(String line, String delimiter) {
+ List result = new ArrayList<>();
+ StringTokenizer st = new StringTokenizer(line, delimiter);
+ while (st.hasMoreTokens()) {
+ result.add(st.nextToken());
+ }
+ return result;
+ }
+
+ public List readFile(Path path, String delimiter) throws IOException {
+
+ List result = new ArrayList<>();
+
+ try (BufferedReader br = new BufferedReader(new FileReader(path.toString()))) {
+
+ String line;
+ while ((line = br.readLine()) != null) {
+ StringTokenizer st = new StringTokenizer(line, delimiter);
+ while (st.hasMoreTokens()) {
+ Integer id = Integer.parseInt(st.nextToken().trim());
+ Double index = Double.parseDouble(st.nextToken().trim());
+ String desc = st.nextToken().trim();
+ result.add(new Trend(id, index, desc));
+ }
+ }
+ }
+ return result;
+ }
+
+ class Trend {
+ private int id;
+ private Double index;
+ private String desc;
+
+ public Trend(int id, Double index, String desc) {
+ this.id = id;
+ this.index = index;
+ this.desc = desc;
+ }
+
+ @Override
+ public String toString() {
+ return "Trend{" +
+ "id=" + id +
+ ", index=" + index +
+ ", desc='" + desc + '\'' +
+ '}';
+ }
+ }
+}
diff --git a/java-string/src/main/java/com/mkyong/string/compare/StringCompare.java b/java-string/src/main/java/com/mkyong/string/compare/StringCompare.java
new file mode 100644
index 0000000..695bfdd
--- /dev/null
+++ b/java-string/src/main/java/com/mkyong/string/compare/StringCompare.java
@@ -0,0 +1,40 @@
+package com.mkyong.string.compare;
+
+public class StringCompare {
+
+ public static void main(String[] args) {
+
+ String str1 = "apple";
+ if (str1.equals("apple")) {
+ System.out.println("I have an apple.");
+ }
+
+ String str2 = "apple";
+ if (str2.equalsIgnoreCase("APPLE")) {
+ System.out.println("I have an APPLE.");
+ }
+
+
+ // true
+ boolean result = new String("mkyong").equals("mkyong");
+ System.out.println(result);
+
+ // true
+ boolean result2 = "mkyong".equals(new String("mkyong"));
+ System.out.println(result2);
+
+ // true
+ boolean result3 = "mkyong".equals("mkyong");
+ System.out.println(result3);
+
+ // false, equals is case-sensitive
+ boolean result4 = new String("mkyong").equals("MKYONG");
+ System.out.println(result4);
+
+ // true, equalsIgnoreCase is case-insensitive
+ boolean result5 = new String("mkyong").equalsIgnoreCase("MKYONG");
+ System.out.println(result5);
+
+ }
+
+}
diff --git a/java-string/src/main/java/com/mkyong/string/compare/StringCompareContentEquals.java b/java-string/src/main/java/com/mkyong/string/compare/StringCompareContentEquals.java
new file mode 100644
index 0000000..6f270d2
--- /dev/null
+++ b/java-string/src/main/java/com/mkyong/string/compare/StringCompareContentEquals.java
@@ -0,0 +1,26 @@
+package com.mkyong.string.compare;
+
+public class StringCompareContentEquals {
+
+ public static void main(String[] args) {
+
+ String str1 = "apple";
+ String str2 = "apple";
+ StringBuilder sb = new StringBuilder("apple");
+ StringBuffer buffer = new StringBuffer("apple");
+
+ // true
+ System.out.println(str1.equals(str2));
+ // false, .equals cant compare StringBuilder
+ System.out.println(str1.equals(sb));
+
+ // .contentEquals supports CharSequence
+ // CharSequence implementations: StringBuffer, StringBuilder, String, etc.
+ // true
+ System.out.println(str1.contentEquals(sb));
+ // true
+ System.out.println(str1.contentEquals(buffer));
+
+ }
+
+}
diff --git a/java-string/src/main/java/com/mkyong/string/compare/StringCompareEquals.java b/java-string/src/main/java/com/mkyong/string/compare/StringCompareEquals.java
new file mode 100644
index 0000000..a1f624f
--- /dev/null
+++ b/java-string/src/main/java/com/mkyong/string/compare/StringCompareEquals.java
@@ -0,0 +1,15 @@
+package com.mkyong.string.compare;
+
+public class StringCompareEquals {
+
+ public static void main(String[] args) {
+
+ String str1 = "apple";
+
+ boolean result = str1.equals("apple");
+
+ System.out.println(result); // true
+
+ }
+
+}
diff --git a/java-string/src/main/java/com/mkyong/string/compare/StringCompareEquals2.java b/java-string/src/main/java/com/mkyong/string/compare/StringCompareEquals2.java
new file mode 100644
index 0000000..a25cb84
--- /dev/null
+++ b/java-string/src/main/java/com/mkyong/string/compare/StringCompareEquals2.java
@@ -0,0 +1,15 @@
+package com.mkyong.string.compare;
+
+public class StringCompareEquals2 {
+
+ public static void main(String[] args) {
+
+ String str1 = "apple";
+
+ boolean result = str1.equals("Apple");
+
+ System.out.println(result); // false
+
+ }
+
+}
diff --git a/java-string/src/main/java/com/mkyong/string/compare/StringCompareEqualsIgnoreCase.java b/java-string/src/main/java/com/mkyong/string/compare/StringCompareEqualsIgnoreCase.java
new file mode 100644
index 0000000..f505261
--- /dev/null
+++ b/java-string/src/main/java/com/mkyong/string/compare/StringCompareEqualsIgnoreCase.java
@@ -0,0 +1,15 @@
+package com.mkyong.string.compare;
+
+public class StringCompareEqualsIgnoreCase {
+
+ public static void main(String[] args) {
+
+ String str1 = "apple";
+
+ boolean result = str1.equalsIgnoreCase("Apple");
+
+ System.out.println(result); // true
+
+ }
+
+}
diff --git a/java-string/src/main/java/com/mkyong/string/compare/StringCompareIntern.java b/java-string/src/main/java/com/mkyong/string/compare/StringCompareIntern.java
new file mode 100644
index 0000000..8775b7b
--- /dev/null
+++ b/java-string/src/main/java/com/mkyong/string/compare/StringCompareIntern.java
@@ -0,0 +1,27 @@
+package com.mkyong.string.compare;
+
+public class StringCompareIntern {
+
+ public static void main(String[] args) {
+
+ String str1 = "apple";
+ String str2 = "apple";
+
+ // true, why true because of the string constant pool
+ System.out.println(str1 == str2);
+
+ String str3 = new String("apple");
+ // false
+ System.out.println(str1 == str3);
+
+ // add this to string pool.
+ String str4 = str3.intern();
+
+ // true
+ System.out.println(str1 == str4);
+
+ // still false
+ System.out.println(str1 == str3);
+
+ }
+}
diff --git a/java-string/src/main/java/com/mkyong/string/compare/StringCompareNull.java b/java-string/src/main/java/com/mkyong/string/compare/StringCompareNull.java
new file mode 100644
index 0000000..45d7743
--- /dev/null
+++ b/java-string/src/main/java/com/mkyong/string/compare/StringCompareNull.java
@@ -0,0 +1,21 @@
+package com.mkyong.string.compare;
+
+public class StringCompareNull {
+
+ public static void main(String[] args) {
+
+ String str1 = null;
+
+ // throw NullPointerException
+ /*if (str1.equals("hello")) {
+ System.out.println("equals");
+ }*/
+
+ // check null
+ if (str1 != null && str1.equals("hello")) {
+ System.out.println("equals");
+ }
+
+ }
+
+}
diff --git a/java-string/src/main/java/com/mkyong/string/compare/StringCompareObjectsEquals.java b/java-string/src/main/java/com/mkyong/string/compare/StringCompareObjectsEquals.java
new file mode 100644
index 0000000..107cbb5
--- /dev/null
+++ b/java-string/src/main/java/com/mkyong/string/compare/StringCompareObjectsEquals.java
@@ -0,0 +1,29 @@
+package com.mkyong.string.compare;
+
+import java.util.Objects;
+
+public class StringCompareObjectsEquals {
+
+ public static void main(String[] args) {
+
+ String str1 = "apple";
+ String str2 = "banana";
+
+ // false
+ System.out.println(Objects.equals(str1, str2));
+
+ // true
+ System.out.println(Objects.equals(str1, new String("apple")));
+
+ // false
+ System.out.println(Objects.equals(null, str2));
+
+ // false
+ System.out.println(Objects.equals(str1, null));
+
+ // true
+ System.out.println(Objects.equals(null, null));
+
+ }
+
+}
diff --git a/java-string/src/main/java/com/mkyong/string/compare/StringCompareTo.java b/java-string/src/main/java/com/mkyong/string/compare/StringCompareTo.java
new file mode 100644
index 0000000..6df5fed
--- /dev/null
+++ b/java-string/src/main/java/com/mkyong/string/compare/StringCompareTo.java
@@ -0,0 +1,48 @@
+package com.mkyong.string.compare;
+
+public class StringCompareTo {
+
+ public static void main(String[] args) {
+
+ System.out.println("-Negative Number-");
+ System.out.println("a".compareTo("b")); // -1
+ System.out.println("a".compareTo("c")); // -2
+ System.out.println("a".compareTo("d")); // -3
+ System.out.println("a".compareTo("e")); // -4
+
+ System.out.println("1".compareTo("2")); // -1
+ System.out.println("1".compareTo("3")); // -2
+ System.out.println("1".compareTo("4")); // -3
+ System.out.println("1".compareTo("5")); // -4
+
+ System.out.println("-Positive Number-");
+ System.out.println("b".compareTo("a")); // 1
+ System.out.println("c".compareTo("a")); // 2
+ System.out.println("d".compareTo("a")); // 3
+ System.out.println("e".compareTo("a")); // 4
+
+ System.out.println("2".compareTo("1")); // 1
+ System.out.println("3".compareTo("1")); // 2
+ System.out.println("4".compareTo("1")); // 3
+ System.out.println("5".compareTo("1")); // 4
+
+ System.out.println("-Zero-");
+ System.out.println("a".compareTo("a")); // 0
+ System.out.println("1".compareTo("1")); // 0
+
+ System.out.println("-Vary Length-");
+ System.out.println("a".compareTo("ab")); // -1
+ System.out.println("a".compareTo("abc")); // -2
+ System.out.println("a".compareTo("abcd")); // -3
+
+ System.out.println("11".compareTo("112")); // -1
+ System.out.println("11".compareTo("1123")); // -2
+ System.out.println("11".compareTo("11234")); // -3
+
+ System.out.println("-compareToIgnoreCase-");
+ System.out.println("a".compareTo("A")); // 32
+ System.out.println("a".compareToIgnoreCase("A")); // 0
+
+ }
+
+}
diff --git a/java-string/src/main/java/com/mkyong/string/split/StringSplit.java b/java-string/src/main/java/com/mkyong/string/split/StringSplit.java
new file mode 100644
index 0000000..d9e416f
--- /dev/null
+++ b/java-string/src/main/java/com/mkyong/string/split/StringSplit.java
@@ -0,0 +1,20 @@
+package com.mkyong.string.split;
+
+public class StringSplit {
+
+ public static void main(String[] args) {
+
+ String phone = "012-3456789";
+ String[] output = phone.split("-");
+
+ System.out.println(output.length); // 2
+
+ String part1 = output[0]; // 012
+ String part2 = output[1]; // 3456789
+
+ System.out.println(part1); // 012
+ System.out.println(part2); // 3456789
+
+ }
+
+}
diff --git a/java-string/src/main/java/com/mkyong/string/split/StringSplitContains.java b/java-string/src/main/java/com/mkyong/string/split/StringSplitContains.java
new file mode 100644
index 0000000..b79902c
--- /dev/null
+++ b/java-string/src/main/java/com/mkyong/string/split/StringSplitContains.java
@@ -0,0 +1,21 @@
+package com.mkyong.string.split;
+
+public class StringSplitContains {
+
+ public static void main(String[] args) {
+
+ String phone = "012-3456789";
+
+ if (phone.contains("-")) {
+
+ String[] output = phone.split("-");
+ System.out.println(output[0]); // 012
+ System.out.println(output[1]); // 3456789
+
+ } else {
+ throw new IllegalArgumentException("String " + phone + " does not contain -");
+ }
+
+ }
+
+}
diff --git a/java-string/src/main/java/com/mkyong/string/split/StringSplitJava8.java b/java-string/src/main/java/com/mkyong/string/split/StringSplitJava8.java
new file mode 100644
index 0000000..8993918
--- /dev/null
+++ b/java-string/src/main/java/com/mkyong/string/split/StringSplitJava8.java
@@ -0,0 +1,25 @@
+package com.mkyong.string.split;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class StringSplitJava8 {
+
+ public static void main(String[] args) {
+
+ String phone = "012-3456789";
+
+ /*List output = Pattern.compile("-")
+ .splitAsStream(phone)
+ .collect(Collectors.toList());*/
+
+ List output = Arrays.stream(phone.split("-"))
+ .collect(Collectors.toList());
+
+ System.out.println(output);
+
+
+ }
+
+}
diff --git a/java-string/src/main/java/com/mkyong/string/split/StringSplitLimit.java b/java-string/src/main/java/com/mkyong/string/split/StringSplitLimit.java
new file mode 100644
index 0000000..bde8c93
--- /dev/null
+++ b/java-string/src/main/java/com/mkyong/string/split/StringSplitLimit.java
@@ -0,0 +1,22 @@
+package com.mkyong.string.split;
+
+public class StringSplitLimit {
+
+ public static void main(String[] args) {
+
+ String phone = "012-345-678-9";
+ String[] output = phone.split("-", 3);
+
+ System.out.println(output.length); // 3
+
+ String part1 = output[0]; // 012
+ String part2 = output[1]; // 345
+ String part3 = output[2]; // 678-9
+
+ System.out.println(part1);
+ System.out.println(part2);
+ System.out.println(part3);
+
+ }
+
+}
diff --git a/java-string/src/main/java/com/mkyong/string/split/StringSplitLookAround.java b/java-string/src/main/java/com/mkyong/string/split/StringSplitLookAround.java
new file mode 100644
index 0000000..cfe9388
--- /dev/null
+++ b/java-string/src/main/java/com/mkyong/string/split/StringSplitLookAround.java
@@ -0,0 +1,27 @@
+package com.mkyong.string.split;
+
+public class StringSplitLookAround {
+
+ public static void main(String[] args) {
+
+ String phone = "012-3456789";
+
+ if (phone.contains("-")) {
+
+ // positive lookahead, split char at right-hand side
+ String[] output = phone.split("(?=-)");
+ System.out.println(output[0]); // 012
+ System.out.println(output[1]); // -3456789
+
+ // positive lookbehind, split char at left-hand side
+ String[] output2 = phone.split("(?<=-)");
+ System.out.println(output2[0]); // 012-
+ System.out.println(output2[1]); // 3456789
+
+ } else {
+ throw new IllegalArgumentException("String " + phone + " does not contain -");
+ }
+
+ }
+
+}
diff --git a/java-string/src/main/java/com/mkyong/string/split/StringSplitMultiDelimiters.java b/java-string/src/main/java/com/mkyong/string/split/StringSplitMultiDelimiters.java
new file mode 100644
index 0000000..ca5e599
--- /dev/null
+++ b/java-string/src/main/java/com/mkyong/string/split/StringSplitMultiDelimiters.java
@@ -0,0 +1,27 @@
+package com.mkyong.string.split;
+
+public class StringSplitMultiDelimiters {
+
+ public static void main(String[] args) {
+
+ String dir = "apple|9|1.88;2.78|0#10";
+ String[] output = dir.split("[|;#]");
+
+ System.out.println(output.length); // 6
+
+ for (String s : output) {
+ System.out.println(s);
+ }
+
+ /*
+ System.out.println(output[0]); // apple
+ System.out.println(output[1]); // 9
+ System.out.println(output[2]); // 1.88
+ System.out.println(output[3]); // 2.78
+ System.out.println(output[4]); // 0
+ System.out.println(output[5]); // 10
+ */
+
+ }
+
+}
diff --git a/java-string/src/main/java/com/mkyong/string/split/StringSplitNewLines.java b/java-string/src/main/java/com/mkyong/string/split/StringSplitNewLines.java
new file mode 100644
index 0000000..95c6a4e
--- /dev/null
+++ b/java-string/src/main/java/com/mkyong/string/split/StringSplitNewLines.java
@@ -0,0 +1,38 @@
+package com.mkyong.string.split;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class StringSplitNewLines {
+
+ public static void main(String[] args) {
+
+ StringBuilder sb = new StringBuilder();
+ sb.append("aaa \n");
+ sb.append("bbb \r\n");
+ sb.append("ccc\n");
+ sb.append("\n");
+ sb.append("ddd\r\n");
+ sb.append("\r\n");
+ sb.append("eee\n");
+
+ String text = sb.toString();
+ System.out.println("---Original---");
+ System.out.println(text);
+
+ System.out.println("---Split---");
+
+ // split by new line, trim and filter empty line
+ List lines = Arrays.stream(text.split("\\r?\\n"))
+ .map(x -> x.trim())
+ .filter(x -> x.length() > 0)
+ .collect(Collectors.toList());
+
+ for (String line : lines) {
+ System.out.println(line);
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/java-string/src/main/java/com/mkyong/string/split/StringSplitSpaces.java b/java-string/src/main/java/com/mkyong/string/split/StringSplitSpaces.java
new file mode 100644
index 0000000..ac21410
--- /dev/null
+++ b/java-string/src/main/java/com/mkyong/string/split/StringSplitSpaces.java
@@ -0,0 +1,16 @@
+package com.mkyong.string.split;
+
+public class StringSplitSpaces {
+
+ public static void main(String[] args) {
+
+ String str = "1 2 3 4 5";
+ String[] output = str.split("\\s+");
+
+ for (String s : output) {
+ System.out.println(s);
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/java-string/src/main/java/com/mkyong/string/split/StringSplitSpecialBackslash.java b/java-string/src/main/java/com/mkyong/string/split/StringSplitSpecialBackslash.java
new file mode 100644
index 0000000..811b361
--- /dev/null
+++ b/java-string/src/main/java/com/mkyong/string/split/StringSplitSpecialBackslash.java
@@ -0,0 +1,22 @@
+package com.mkyong.string.split;
+
+import java.util.regex.Pattern;
+
+public class StringSplitSpecialBackslash {
+
+ public static void main(String[] args) {
+
+ String dir = "C:\\Users\\mkyong\\projects\\mkyong-tutorials";
+
+ // three ways to escape regex special character
+ // String[] output = dir.split("\\\\");
+ // String[] output = dir.split("[\\\\]");
+ String[] output = dir.split(Pattern.quote("\\"));
+
+ for (String s : output) {
+ System.out.println(s);
+ }
+
+ }
+
+}
diff --git a/java-string/src/main/java/com/mkyong/string/split/StringSplitSpecialPeriod.java b/java-string/src/main/java/com/mkyong/string/split/StringSplitSpecialPeriod.java
new file mode 100644
index 0000000..8e8c584
--- /dev/null
+++ b/java-string/src/main/java/com/mkyong/string/split/StringSplitSpecialPeriod.java
@@ -0,0 +1,22 @@
+package com.mkyong.string.split;
+
+import java.util.regex.Pattern;
+
+public class StringSplitSpecialPeriod {
+
+ public static void main(String[] args) {
+
+ String dir = "a.b.c.d.e";
+
+ // three ways to escape regex special character
+ //String[] output = dir.split("\\.");
+ //String[] output = dir.split("[.]");
+ String[] output = dir.split(Pattern.quote("."));
+
+ for (String s : output) {
+ System.out.println(s);
+ }
+
+ }
+
+}
diff --git a/java-string/src/main/java/com/mkyong/string/split/StringSplitSpecialPipe.java b/java-string/src/main/java/com/mkyong/string/split/StringSplitSpecialPipe.java
new file mode 100644
index 0000000..a57b5fa
--- /dev/null
+++ b/java-string/src/main/java/com/mkyong/string/split/StringSplitSpecialPipe.java
@@ -0,0 +1,24 @@
+package com.mkyong.string.split;
+
+import java.util.regex.Pattern;
+
+public class StringSplitSpecialPipe {
+
+ public static void main(String[] args) {
+
+ String csv = "a|b|c|d";
+
+ // three ways to escape regex special character
+ // String[] output = csv.split("\\|");
+ // String[] output = csv.split("[|]");
+ String[] output = csv.split(Pattern.quote("|"));
+
+ //System.out.println(output.length);
+
+ for (String s : output) {
+ System.out.println(s);
+ }
+
+ }
+
+}
diff --git a/java-string/src/main/java/com/mkyong/string/split/StringSplitStringTokenizer.java b/java-string/src/main/java/com/mkyong/string/split/StringSplitStringTokenizer.java
new file mode 100644
index 0000000..06afdb4
--- /dev/null
+++ b/java-string/src/main/java/com/mkyong/string/split/StringSplitStringTokenizer.java
@@ -0,0 +1,21 @@
+package com.mkyong.string.split;
+
+import java.util.StringTokenizer;
+
+// This `StringTokenizer` is a legacy class, retained for compatibility reasons;
+// the use is discouraged! Please upgrade the code to `String#split()`.
+public class StringSplitStringTokenizer {
+
+ public static void main(String[] args) {
+
+ String test = "abc.def.123";
+ // the delimiter is a string, not regex, no need to escape the dot
+ StringTokenizer token = new StringTokenizer(test, ".");
+
+ while (token.hasMoreTokens()) {
+ System.out.println(token.nextToken());
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/java-string/src/main/java/com/mkyong/string/utils/CustomStringUtils.java b/java-string/src/main/java/com/mkyong/string/utils/CustomStringUtils.java
new file mode 100644
index 0000000..b50d6bb
--- /dev/null
+++ b/java-string/src/main/java/com/mkyong/string/utils/CustomStringUtils.java
@@ -0,0 +1,27 @@
+package com.mkyong.string.utils;
+
+public class CustomStringUtils {
+
+ public static boolean isNumber(String input) {
+
+ // if null return false.
+ if (input == null) return false;
+
+ // trim for extra spaces
+ input = input.trim();
+
+ // if empty return false
+ if ("".equals(input)) return false;
+
+ if (input.startsWith("-") || input.startsWith("+")) {
+ // positive or negative numbers, cut the first char
+ // +1 -> 1, -1 -> 1
+ return input.substring(1).matches("[0-9]+");
+ } else {
+ // other numbers, let check it
+ return input.matches("[0-9]+");
+ }
+
+ }
+
+}
diff --git a/java-string/src/test/java/com.mkyong.string/ConvertStringToIntTest.java b/java-string/src/test/java/com.mkyong.string/ConvertStringToIntTest.java
new file mode 100644
index 0000000..89c6f40
--- /dev/null
+++ b/java-string/src/test/java/com.mkyong.string/ConvertStringToIntTest.java
@@ -0,0 +1,64 @@
+package com.mkyong.string;
+
+import org.apache.commons.lang3.StringUtils;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.MethodSource;
+import org.junit.jupiter.params.provider.NullSource;
+import org.junit.jupiter.params.provider.ValueSource;
+
+import java.util.stream.Stream;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+public class ConvertStringToIntTest {
+
+ /*@ParameterizedTest(name = "#{index} - Run test with args={0}")
+ @MethodSource("stringProvider")
+ void testMethod(String input, int expected) {
+ assertEquals(Integer.parseInt(input), expected);
+ }
+
+ static Stream stringProvider() {
+ return Stream.of(
+ arguments("20", 20),
+ arguments("+20", 20),
+ arguments("-20", -20)
+ );
+ }*/
+
+ /*@ParameterizedTest(name = "#{index} - Run test with args={0}")
+ @ValueSource(strings = {" 1", "1 ", " 1 ", "+1", "-1", "100", "999", "2147483647"})
+ void testStringToNumberValid(String input) {
+ assertTrue(StringUtils.isNumeric(input));
+ }
+
+ @ParameterizedTest(name = "#{index} - Run test with args={0}")
+ @ValueSource(strings = {"10A", "++1", "--1", "1.1", "10-1", "A10", "2147483648"})
+ void testStringToNumberInValid(String input) {
+ assertFalse(StringUtils.isNumeric(input));
+ }*/
+
+ @ParameterizedTest(name = "#{index} - Run test with args={0}")
+ @NullSource
+ @ValueSource(strings = {"", " "})
+ void testBlankIncludeNull3(String input) {
+ assertTrue(StringUtils.isBlank(input));
+ }
+
+ @ParameterizedTest(name = "#{index} - Run test with args={0}")
+ @NullSource
+ @ValueSource(strings = {"", " "})
+ void testBlankIncludeNull(String input) {
+ assertTrue(StringUtils.isBlank(input));
+ }
+
+ @ParameterizedTest(name = "#{index} - Run test with args={0}")
+ @MethodSource("blankOrNullStrings")
+ void testBlankIncludeNull2(String input) {
+ assertTrue(StringUtils.isBlank(input));
+ }
+
+ static Stream blankOrNullStrings() {
+ return Stream.of("", " ", null);
+ }
+}
diff --git a/java-xml/src/main/java/com/mkyong/xml/jdom/ModifyXmlJDomParser.java b/java-xml/src/main/java/com/mkyong/xml/jdom/ModifyXmlJDomParser.java
index 7334e6e..fd5f102 100644
--- a/java-xml/src/main/java/com/mkyong/xml/jdom/ModifyXmlJDomParser.java
+++ b/java-xml/src/main/java/com/mkyong/xml/jdom/ModifyXmlJDomParser.java
@@ -9,6 +9,7 @@
import org.jdom2.output.Format;
import org.jdom2.output.XMLOutputter;
+import javax.xml.XMLConstants;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
@@ -21,6 +22,12 @@ public class ModifyXmlJDomParser {
public static void main(String[] args) throws JDOMException, IOException {
SAXBuilder sax = new SAXBuilder();
+
+ // https://rules.sonarsource.com/java/RSPEC-2755
+ // prevent xxe
+ sax.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, "");
+ sax.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
+
Document doc = sax.build(new File(FILENAME));
Element rootNode = doc.getRootElement();
diff --git a/java-xml/src/main/java/com/mkyong/xml/jdom/ReadXmlAlexaApiJDomParser.java b/java-xml/src/main/java/com/mkyong/xml/jdom/ReadXmlAlexaApiJDomParser.java
index 87bdeef..0207485 100644
--- a/java-xml/src/main/java/com/mkyong/xml/jdom/ReadXmlAlexaApiJDomParser.java
+++ b/java-xml/src/main/java/com/mkyong/xml/jdom/ReadXmlAlexaApiJDomParser.java
@@ -5,6 +5,7 @@
import org.jdom2.JDOMException;
import org.jdom2.input.SAXBuilder;
+import javax.xml.XMLConstants;
import java.io.IOException;
import java.net.URL;
import java.util.List;
@@ -18,6 +19,12 @@ public static void main(String[] args) {
try {
SAXBuilder sax = new SAXBuilder();
+
+ // https://rules.sonarsource.com/java/RSPEC-2755
+ // prevent xxe
+ sax.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, "");
+ sax.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
+
// XML is in a web-based location
Document doc = sax.build(new URL(REMOTE_URL));
diff --git a/java-xml/src/main/java/com/mkyong/xml/jdom/ReadXmlJDomParser.java b/java-xml/src/main/java/com/mkyong/xml/jdom/ReadXmlJDomParser.java
index fe3eae3..545c09e 100644
--- a/java-xml/src/main/java/com/mkyong/xml/jdom/ReadXmlJDomParser.java
+++ b/java-xml/src/main/java/com/mkyong/xml/jdom/ReadXmlJDomParser.java
@@ -5,6 +5,7 @@
import org.jdom2.JDOMException;
import org.jdom2.input.SAXBuilder;
+import javax.xml.XMLConstants;
import java.io.File;
import java.io.IOException;
import java.util.List;
@@ -13,6 +14,7 @@
public class ReadXmlJDomParser {
private static final String FILENAME = "src/main/resources/staff.xml";
+
//private static final String FILENAME = "c://test//staff.xml";
// https://github.com/hunterhacker/jdom/wiki/JDOM2-A-Primer
@@ -21,6 +23,12 @@ public static void main(String[] args) {
try {
SAXBuilder sax = new SAXBuilder();
+
+ // https://rules.sonarsource.com/java/RSPEC-2755
+ // prevent xxe
+ sax.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, "");
+ sax.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
+
// XML is a local file
Document doc = sax.build(new File(FILENAME));
diff --git a/java-xml/src/main/java/com/mkyong/xml/jdom/WriteXmlJDom.java b/java-xml/src/main/java/com/mkyong/xml/jdom/WriteXmlJDom.java
index e1c22c7..5924192 100644
--- a/java-xml/src/main/java/com/mkyong/xml/jdom/WriteXmlJDom.java
+++ b/java-xml/src/main/java/com/mkyong/xml/jdom/WriteXmlJDom.java
@@ -114,4 +114,4 @@ private static void writeSimpleXml() throws JDOMException, IOException {
}
-}
+}
\ No newline at end of file
diff --git a/java-xml/src/main/java/com/mkyong/xml/sax/ReadXmlSaxParser.java b/java-xml/src/main/java/com/mkyong/xml/sax/ReadXmlSaxParser.java
index b6ced15..cc35a4f 100644
--- a/java-xml/src/main/java/com/mkyong/xml/sax/ReadXmlSaxParser.java
+++ b/java-xml/src/main/java/com/mkyong/xml/sax/ReadXmlSaxParser.java
@@ -1,7 +1,8 @@
package com.mkyong.xml.sax;
-import com.mkyong.xml.sax.handler.CountElementHandlerSax;
+import com.mkyong.xml.sax.handler.PrintAllHandlerSax;
import org.xml.sax.SAXException;
+
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
@@ -19,10 +20,15 @@ public static void main(String[] args) {
try {
+ // https://rules.sonarsource.com/java/RSPEC-2755
+ // prevent XXE, completely disable DOCTYPE declaration:
+ // factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
+
SAXParser saxParser = factory.newSAXParser();
- // PrintAllHandlerSax handler = new PrintAllHandlerSax();
- // saxParser.parse(FILENAME, handler);
+ PrintAllHandlerSax handler = new PrintAllHandlerSax();
+
+ saxParser.parse(FILENAME, handler);
/*XMLReader xmlReader = saxParser.getXMLReader();
xmlReader.setContentHandler(handler);
@@ -32,10 +38,10 @@ public static void main(String[] args) {
xmlReader.parse(source);*/
// count elements name known as "staff"
- CountElementHandlerSax countStaffHandler = new CountElementHandlerSax("staff");
+ /*CountElementHandlerSax countStaffHandler = new CountElementHandlerSax("staff");
saxParser.parse(FILENAME, countStaffHandler);
- System.out.println("Number of staff elements : " + countStaffHandler.getCount());
+ System.out.println("Number of staff elements : " + countStaffHandler.getCount());*/
} catch (ParserConfigurationException | SAXException | IOException e) {
e.printStackTrace();
@@ -43,4 +49,4 @@ public static void main(String[] args) {
}
-}
+}
\ No newline at end of file
diff --git a/java-xml/src/main/java/com/mkyong/xml/sax/ReadXmlSaxParserXXE.java b/java-xml/src/main/java/com/mkyong/xml/sax/ReadXmlSaxParserXXE.java
new file mode 100644
index 0000000..c26ed51
--- /dev/null
+++ b/java-xml/src/main/java/com/mkyong/xml/sax/ReadXmlSaxParserXXE.java
@@ -0,0 +1,38 @@
+package com.mkyong.xml.sax;
+
+import com.mkyong.xml.sax.handler.PrintAllHandlerSax;
+import org.xml.sax.SAXException;
+
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+import java.io.IOException;
+
+public class ReadXmlSaxParserXXE {
+
+ //private static final String FILENAME = "src/main/resources/staff.xml";
+ private static final String FILENAME = "src/main/resources/staff-xxe.xml";
+
+ public static void main(String[] args) {
+
+ SAXParserFactory factory = SAXParserFactory.newInstance();
+
+ try {
+
+ // https://rules.sonarsource.com/java/RSPEC-2755
+ // prevent XXE, completely disable DOCTYPE declaration:
+ factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
+
+ SAXParser saxParser = factory.newSAXParser();
+
+ PrintAllHandlerSax handler = new PrintAllHandlerSax();
+
+ saxParser.parse(FILENAME, handler);
+
+ } catch (ParserConfigurationException | SAXException | IOException e) {
+ e.printStackTrace();
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/java-xml/src/main/java/com/mkyong/xml/stax/ReadXmlStAXCursorParser.java b/java-xml/src/main/java/com/mkyong/xml/stax/ReadXmlStAXCursorParser.java
index bc3872a..91b80df 100644
--- a/java-xml/src/main/java/com/mkyong/xml/stax/ReadXmlStAXCursorParser.java
+++ b/java-xml/src/main/java/com/mkyong/xml/stax/ReadXmlStAXCursorParser.java
@@ -1,19 +1,14 @@
package com.mkyong.xml.stax;
-import javax.xml.namespace.QName;
-import javax.xml.stream.XMLEventReader;
+import javax.xml.XMLConstants;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
-import javax.xml.stream.events.Attribute;
-import javax.xml.stream.events.EndElement;
-import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.nio.file.Path;
import java.nio.file.Paths;
-import java.util.Arrays;
public class ReadXmlStAXCursorParser {
@@ -76,6 +71,12 @@ private static void printXmlByXmlCursorReader(Path path)
throws FileNotFoundException, XMLStreamException {
XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
+
+ // https://rules.sonarsource.com/java/RSPEC-2755
+ // prevent xxe
+ xmlInputFactory.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, "");
+ xmlInputFactory.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
+
XMLStreamReader reader = xmlInputFactory.createXMLStreamReader(
new FileInputStream(path.toFile()));
diff --git a/java-xml/src/main/java/com/mkyong/xml/stax/ReadXmlStAXEventParser.java b/java-xml/src/main/java/com/mkyong/xml/stax/ReadXmlStAXEventParser.java
index acbfb6a..9cccb18 100644
--- a/java-xml/src/main/java/com/mkyong/xml/stax/ReadXmlStAXEventParser.java
+++ b/java-xml/src/main/java/com/mkyong/xml/stax/ReadXmlStAXEventParser.java
@@ -1,5 +1,6 @@
package com.mkyong.xml.stax;
+import javax.xml.XMLConstants;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLInputFactory;
@@ -33,6 +34,12 @@ private static void printXmlByXmlEventReader(Path path)
throws FileNotFoundException, XMLStreamException {
XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
+
+ // https://rules.sonarsource.com/java/RSPEC-2755
+ // prevent xxe
+ xmlInputFactory.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, "");
+ xmlInputFactory.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
+
XMLEventReader reader = xmlInputFactory.createXMLEventReader(
new FileInputStream(path.toFile()));
diff --git a/java-xml/src/main/java/com/mkyong/xml/tips/ConvertStringToXmlDom.java b/java-xml/src/main/java/com/mkyong/xml/tips/ConvertStringToXmlDom.java
new file mode 100644
index 0000000..3b962e4
--- /dev/null
+++ b/java-xml/src/main/java/com/mkyong/xml/tips/ConvertStringToXmlDom.java
@@ -0,0 +1,89 @@
+package com.mkyong.xml.tips;
+
+import org.w3c.dom.Document;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+import javax.xml.XMLConstants;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+import java.io.IOException;
+import java.io.StringReader;
+import java.io.StringWriter;
+
+// DOM Parser
+public class ConvertStringToXmlDom {
+
+ final static String str = "\n" +
+ "\n" +
+ " \n" +
+ " mkyong\n" +
+ " support\n" +
+ " 5000\n" +
+ " \n" +
+ " testing]]>\n" +
+ " \n" +
+ " \n" +
+ " yflow\n" +
+ " admin\n" +
+ " 8000\n" +
+ " \n" +
+ " \n" +
+ "";
+
+ public static void main(String[] args) {
+
+ // String to XML Document
+ Document document = convertStringToXml(str);
+
+ // XML Document to String
+ String xml = convertXmlToString(document);
+
+ System.out.println(xml);
+
+ }
+
+ private static String convertXmlToString(Document doc) {
+ DOMSource domSource = new DOMSource(doc);
+ StringWriter writer = new StringWriter();
+ StreamResult result = new StreamResult(writer);
+ TransformerFactory tf = TransformerFactory.newInstance();
+ Transformer transformer = null;
+ try {
+ transformer = tf.newTransformer();
+ transformer.transform(domSource, result);
+ } catch (TransformerException e) {
+ throw new RuntimeException(e);
+ }
+ return writer.toString();
+ }
+
+ private static Document convertStringToXml(String xmlString) {
+
+ DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+
+ try {
+
+ // optional, but recommended
+ // process XML securely, avoid attacks like XML External Entities (XXE)
+ dbf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
+
+ DocumentBuilder builder = dbf.newDocumentBuilder();
+
+ Document doc = builder.parse(new InputSource(new StringReader(xmlString)));
+
+ return doc;
+
+ } catch (ParserConfigurationException | IOException | SAXException e) {
+ throw new RuntimeException(e);
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/java-xml/src/main/java/com/mkyong/xml/tips/ConvertStringToXmlJDom2.java b/java-xml/src/main/java/com/mkyong/xml/tips/ConvertStringToXmlJDom2.java
new file mode 100644
index 0000000..748b3c5
--- /dev/null
+++ b/java-xml/src/main/java/com/mkyong/xml/tips/ConvertStringToXmlJDom2.java
@@ -0,0 +1,79 @@
+package com.mkyong.xml.tips;
+
+import org.jdom2.Document;
+import org.jdom2.JDOMException;
+import org.jdom2.input.SAXBuilder;
+import org.jdom2.output.Format;
+import org.jdom2.output.XMLOutputter;
+
+import javax.xml.XMLConstants;
+import java.io.IOException;
+import java.io.StringReader;
+import java.io.StringWriter;
+
+// JDOM2 Parser
+public class ConvertStringToXmlJDom2 {
+
+ final static String str = "\n" +
+ "\n" +
+ " \n" +
+ " mkyong\n" +
+ " support\n" +
+ " 5000\n" +
+ " \n" +
+ " testing]]>\n" +
+ " \n" +
+ " \n" +
+ " yflow\n" +
+ " admin\n" +
+ " 8000\n" +
+ " \n" +
+ " \n" +
+ "";
+
+ public static void main(String[] args) {
+
+ // String to XML Document
+ Document document = convertStringToXml(str);
+
+ // XML Document to String
+ String xml = convertXmlDocumentToString(document);
+
+ System.out.println(xml);
+
+ }
+
+ private static String convertXmlDocumentToString(Document doc) {
+ XMLOutputter xmlOutput = new XMLOutputter();
+ xmlOutput.setFormat(Format.getPrettyFormat());
+
+ StringWriter result = new StringWriter();
+ try {
+ xmlOutput.output(doc, result);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ return result.toString();
+ }
+
+ private static Document convertStringToXml(String xmlString) {
+
+ SAXBuilder sax = new SAXBuilder();
+
+ // https://rules.sonarsource.com/java/RSPEC-2755
+ // prevent xxe
+ sax.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, "");
+ sax.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
+
+ try {
+
+ Document doc = sax.build(new StringReader(xmlString));
+ return doc;
+
+ } catch (JDOMException | IOException e) {
+ throw new RuntimeException(e);
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/java-xml/src/main/resources/staff-xxe.xml b/java-xml/src/main/resources/staff-xxe.xml
new file mode 100644
index 0000000..60632ec
--- /dev/null
+++ b/java-xml/src/main/resources/staff-xxe.xml
@@ -0,0 +1,11 @@
+
+ ]>
+
+
+ &xxe;
+ support
+ 5000
+
+ testing]]>
+
+
\ No newline at end of file