Skip to content

Commit 07a834c

Browse files
committed
Sync with underscore-java
1 parent 05c0776 commit 07a834c

File tree

9 files changed

+792
-91
lines changed

9 files changed

+792
-91
lines changed

src/main/java/com/github/underscore/U.java

Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,20 @@
2626
import java.io.FileInputStream;
2727
import java.io.FileOutputStream;
2828
import java.io.IOException;
29+
import java.io.InputStream;
30+
import java.io.OutputStream;
2931
import java.net.URI;
3032
import java.net.URISyntaxException;
3133
import java.net.URL;
3234
import java.nio.channels.Channels;
3335
import java.nio.channels.ReadableByteChannel;
3436
import java.nio.charset.StandardCharsets;
37+
import java.nio.file.FileVisitResult;
3538
import java.nio.file.Files;
39+
import java.nio.file.Path;
3640
import java.nio.file.Paths;
41+
import java.nio.file.SimpleFileVisitor;
42+
import java.nio.file.attribute.BasicFileAttributes;
3743
import java.util.ArrayList;
3844
import java.util.Arrays;
3945
import java.util.Collection;
@@ -100,6 +106,7 @@ public class U<T> extends Underscore<T> {
100106
java.util.regex.Pattern.compile(
101107
UPPER + "+(?=" + UPPER + LOWER + ")|" + UPPER + "?" + LOWER + "|" + UPPER
102108
+ "+|\\d+");
109+
private static final String ENCODING = "#encoding";
103110

104111
static {
105112
String[] deburredLetters =
@@ -2781,6 +2788,206 @@ public static String xmlToJson(String xml, XmlToJsonMode mode) {
27812788
return xmlToJson(xml, Json.JsonStringBuilder.Step.TWO_SPACES, mode);
27822789
}
27832790

2791+
public static void fileXmlToJson(
2792+
String xmlFileName, String jsonFileName, Json.JsonStringBuilder.Step identStep)
2793+
throws IOException {
2794+
final byte[] bytes = Files.readAllBytes(Paths.get(xmlFileName));
2795+
String xmlText = new String(removeBom(bytes), detectEncoding(bytes));
2796+
Files.write(
2797+
Paths.get(jsonFileName),
2798+
formatString(xmlToJson(xmlText, identStep), System.lineSeparator())
2799+
.getBytes(StandardCharsets.UTF_8));
2800+
}
2801+
2802+
public static void fileXmlToJson(String xmlFileName, String jsonFileName) throws IOException {
2803+
fileXmlToJson(xmlFileName, jsonFileName, Json.JsonStringBuilder.Step.TWO_SPACES);
2804+
}
2805+
2806+
public static void streamXmlToJson(
2807+
InputStream xmlInputStream,
2808+
OutputStream jsonOutputStream,
2809+
Json.JsonStringBuilder.Step indentStep)
2810+
throws IOException {
2811+
byte[] bytes = xmlInputStream.readAllBytes();
2812+
String encoding = detectEncoding(bytes);
2813+
String xmlText = new String(removeBom(bytes), encoding);
2814+
String jsonText = xmlToJson(xmlText, indentStep);
2815+
String formattedJson = formatString(jsonText, System.lineSeparator());
2816+
jsonOutputStream.write(formattedJson.getBytes(StandardCharsets.UTF_8));
2817+
}
2818+
2819+
public static void streamXmlToJson(InputStream xmlInputStream, OutputStream jsonOutputStream)
2820+
throws IOException {
2821+
streamXmlToJson(xmlInputStream, jsonOutputStream, Json.JsonStringBuilder.Step.TWO_SPACES);
2822+
}
2823+
2824+
public static void fileJsonToXml(
2825+
String jsonFileName, String xmlFileName, Xml.XmlStringBuilder.Step identStep)
2826+
throws IOException {
2827+
final byte[] bytes = Files.readAllBytes(Paths.get(jsonFileName));
2828+
String jsonText = new String(removeBom(bytes), detectEncoding(bytes));
2829+
Object result = U.fromJson(jsonText);
2830+
Path xmlFilePath = Paths.get(xmlFileName);
2831+
String lineSeparator = System.lineSeparator();
2832+
if (result instanceof Map) {
2833+
if (((Map) result).containsKey(ENCODING)) {
2834+
String encoding = String.valueOf(((Map) result).get(ENCODING));
2835+
Files.write(
2836+
xmlFilePath,
2837+
formatString(Xml.toXml((Map) result, identStep), lineSeparator)
2838+
.getBytes(encoding));
2839+
} else {
2840+
Files.write(
2841+
xmlFilePath,
2842+
formatString(Xml.toXml((Map) result, identStep), lineSeparator)
2843+
.getBytes(StandardCharsets.UTF_8));
2844+
}
2845+
} else {
2846+
Files.write(
2847+
xmlFilePath,
2848+
formatString(Xml.toXml((List) result, identStep), lineSeparator)
2849+
.getBytes(StandardCharsets.UTF_8));
2850+
}
2851+
}
2852+
2853+
public static void fileJsonToXml(String jsonFileName, String xmlFileName) throws IOException {
2854+
fileJsonToXml(jsonFileName, xmlFileName, Xml.XmlStringBuilder.Step.TWO_SPACES);
2855+
}
2856+
2857+
public static void jsonFolderToXml(
2858+
String jsonFolder, String xmlFolder, Xml.XmlStringBuilder.Step identStep)
2859+
throws IOException {
2860+
Path sourceRoot = Paths.get(jsonFolder);
2861+
Path targetRoot = Paths.get(xmlFolder);
2862+
Files.walkFileTree(sourceRoot, new SimpleFileVisitor<>() {
2863+
@Override
2864+
public FileVisitResult visitFile(Path path, BasicFileAttributes attrs) throws IOException {
2865+
covertJsonToXml(path, sourceRoot, targetRoot, identStep);
2866+
return FileVisitResult.CONTINUE;
2867+
}
2868+
});
2869+
}
2870+
2871+
public static void jsonFolderToXml(String jsonFolder, String xmlFolder) throws IOException {
2872+
jsonFolderToXml(jsonFolder, xmlFolder, Xml.XmlStringBuilder.Step.TWO_SPACES);
2873+
}
2874+
2875+
public static void covertJsonToXml(Path path, Path sourceRoot, Path targetRoot,
2876+
Xml.XmlStringBuilder.Step identStep) throws IOException {
2877+
Path relativePath = sourceRoot.relativize(path);
2878+
String fileName = relativePath.getFileName().toString();
2879+
String xmlFileName;
2880+
if (fileName.endsWith(".json")) {
2881+
xmlFileName = fileName.substring(0, fileName.length() - 5) + ".xml";
2882+
} else {
2883+
return;
2884+
}
2885+
Path targetPath = targetRoot.resolve(relativePath).getParent().resolve(xmlFileName);
2886+
Files.createDirectories(targetPath.getParent());
2887+
fileJsonToXml(path.toAbsolutePath().toString(), targetPath.toString(), identStep);
2888+
}
2889+
2890+
public static void streamJsonToXml(
2891+
InputStream jsonInputStream,
2892+
OutputStream xmlOutputStream,
2893+
Xml.XmlStringBuilder.Step identStep)
2894+
throws IOException {
2895+
byte[] bytes = jsonInputStream.readAllBytes();
2896+
String jsonText = new String(removeBom(bytes), detectEncoding(bytes));
2897+
Object jsonObject = U.fromJson(jsonText);
2898+
String lineSeparator = System.lineSeparator();
2899+
String xml;
2900+
if (jsonObject instanceof Map) {
2901+
xml = formatString(Xml.toXml((Map<?, ?>) jsonObject, identStep), lineSeparator);
2902+
if (((Map) jsonObject).containsKey(ENCODING)) {
2903+
String encoding = String.valueOf(((Map) jsonObject).get(ENCODING));
2904+
xmlOutputStream.write(xml.getBytes(encoding));
2905+
} else {
2906+
xmlOutputStream.write(xml.getBytes(StandardCharsets.UTF_8));
2907+
}
2908+
} else {
2909+
xml = formatString(Xml.toXml((List<?>) jsonObject, identStep), lineSeparator);
2910+
xmlOutputStream.write(xml.getBytes(StandardCharsets.UTF_8));
2911+
}
2912+
}
2913+
2914+
public static void streamJsonToXml(InputStream jsonInputStream, OutputStream xmlOutputStream)
2915+
throws IOException {
2916+
streamJsonToXml(jsonInputStream, xmlOutputStream, Xml.XmlStringBuilder.Step.TWO_SPACES);
2917+
}
2918+
2919+
public static byte[] removeBom(byte[] bytes) {
2920+
if ((bytes.length >= 3) && (bytes[0] == -17) && (bytes[1] == -69) && (bytes[2] == -65)) {
2921+
return Arrays.copyOfRange(bytes, 3, bytes.length);
2922+
}
2923+
if ((bytes.length >= 2) && (bytes[0] == -1) && (bytes[1] == -2)) {
2924+
return Arrays.copyOfRange(bytes, 2, bytes.length);
2925+
}
2926+
if ((bytes.length >= 2) && (bytes[0] == -2) && (bytes[1] == -1)) {
2927+
return Arrays.copyOfRange(bytes, 2, bytes.length);
2928+
}
2929+
return bytes;
2930+
}
2931+
2932+
public static String detectEncoding(byte[] buffer) {
2933+
if (buffer.length < 4) {
2934+
return "UTF8";
2935+
}
2936+
String encoding = null;
2937+
int n =
2938+
((buffer[0] & 0xFF) << 24)
2939+
| ((buffer[1] & 0xFF) << 16)
2940+
| ((buffer[2] & 0xFF) << 8)
2941+
| (buffer[3] & 0xFF);
2942+
switch (n) {
2943+
case 0x0000FEFF:
2944+
case 0x0000003C:
2945+
encoding = "UTF_32BE";
2946+
break;
2947+
case 0x003C003F:
2948+
encoding = "UnicodeBigUnmarked";
2949+
break;
2950+
case 0xFFFE0000:
2951+
case 0x3C000000:
2952+
encoding = "UTF_32LE";
2953+
break;
2954+
// <?
2955+
case 0x3C003F00:
2956+
encoding = "UnicodeLittleUnmarked";
2957+
break;
2958+
// <?xm
2959+
case 0x3C3F786D:
2960+
encoding = "UTF8";
2961+
break;
2962+
default:
2963+
if ((n >>> 8) == 0xEFBBBF) {
2964+
encoding = "UTF8";
2965+
break;
2966+
}
2967+
if ((n >>> 24) == 0x3C) {
2968+
break;
2969+
}
2970+
switch (n >>> 16) {
2971+
case 0xFFFE:
2972+
encoding = "UnicodeLittleUnmarked";
2973+
break;
2974+
case 0xFEFF:
2975+
encoding = "UnicodeBigUnmarked";
2976+
break;
2977+
default:
2978+
break;
2979+
}
2980+
}
2981+
return encoding == null ? "UTF8" : encoding;
2982+
}
2983+
2984+
public static String formatString(String data, String lineSeparator) {
2985+
if ("\n".equals(lineSeparator)) {
2986+
return data;
2987+
}
2988+
return data.replace("\n", lineSeparator);
2989+
}
2990+
27842991
public static String xmlOrJsonToJson(String xmlOrJson, Json.JsonStringBuilder.Step identStep) {
27852992
TextType textType = getTextType(xmlOrJson);
27862993
final String result;

src/main/java/com/github/underscore/Underscore.java

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
* The MIT License (MIT)
33
*
4-
* Copyright 2015-2024 Valentyn Kolesnikov
4+
* Copyright 2015-2025 Valentyn Kolesnikov
55
*
66
* Permission is hereby granted, free of charge, to any person obtaining a copy
77
* of this software and associated documentation files (the "Software"), to deal
@@ -2098,13 +2098,12 @@ public static <T> java.util.concurrent.ScheduledFuture<T> delay(
20982098
final Supplier<T> function, final int delayMilliseconds) {
20992099
final java.util.concurrent.ScheduledExecutorService scheduler =
21002100
java.util.concurrent.Executors.newSingleThreadScheduledExecutor();
2101-
final java.util.concurrent.ScheduledFuture<T> future =
2102-
scheduler.schedule(
2103-
function::get,
2104-
delayMilliseconds,
2105-
java.util.concurrent.TimeUnit.MILLISECONDS);
2106-
scheduler.shutdown();
2107-
return future;
2101+
try {
2102+
return scheduler.schedule(
2103+
function::get, delayMilliseconds, java.util.concurrent.TimeUnit.MILLISECONDS);
2104+
} finally {
2105+
scheduler.shutdown();
2106+
}
21082107
}
21092108

21102109
public static <T> java.util.concurrent.ScheduledFuture<T> defer(final Supplier<T> function) {
@@ -3318,11 +3317,14 @@ public static <T> String join(final Iterable<T> iterable, final String separator
33183317
return sb.toString();
33193318
}
33203319

3321-
public static <T> String joinToString(final Iterable<T> iterable, final String separator,
3322-
final String prefix, final String postfix,
3323-
final int limit,
3324-
final String truncated,
3325-
final Function<T, String> transform) {
3320+
public static <T> String joinToString(
3321+
final Iterable<T> iterable,
3322+
final String separator,
3323+
final String prefix,
3324+
final String postfix,
3325+
final int limit,
3326+
final String truncated,
3327+
final Function<T, String> transform) {
33263328
final StringBuilder sb = new StringBuilder();
33273329
int index = 0;
33283330
if (prefix != null) {
@@ -3343,7 +3345,8 @@ public static <T> String joinToString(final Iterable<T> iterable, final String s
33433345
return sb.toString();
33443346
}
33453347

3346-
private static void joinToStringPostfix(String postfix, int limit, String truncated, int index, StringBuilder sb) {
3348+
private static void joinToStringPostfix(
3349+
String postfix, int limit, String truncated, int index, StringBuilder sb) {
33473350
if (limit >= 0 && index > limit) {
33483351
sb.append(truncated == null ? "..." : truncated);
33493352
}
@@ -3624,6 +3627,7 @@ public static <T> java.util.concurrent.ScheduledFuture setInterval(
36243627
final Supplier<T> function, final int delayMilliseconds) {
36253628
final java.util.concurrent.ScheduledExecutorService scheduler =
36263629
java.util.concurrent.Executors.newSingleThreadScheduledExecutor();
3630+
Runtime.getRuntime().addShutdownHook(new Thread(scheduler::shutdown));
36273631
return scheduler.scheduleAtFixedRate(
36283632
function::get,
36293633
delayMilliseconds,

src/test/java/com/github/underscore/ArraysTest.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,7 @@ void chunkFill() {
318318
@Test
319319
void cycle() {
320320
assertEquals("[]", Underscore.cycle(Underscore.range(5), 0).toString());
321-
assertEquals("[]", Underscore.cycle(new ArrayList<Object>(), 5).toString());
321+
assertEquals("[]", Underscore.cycle(new ArrayList<>(), 5).toString());
322322
assertEquals("[4, 3, 2, 1, 0]", Underscore.cycle(Underscore.range(5), -1).toString());
323323
assertEquals(
324324
"[0, 1, 2, 0, 1, 2, 0, 1, 2]", Underscore.cycle(Underscore.range(3), 3).toString());
@@ -370,8 +370,8 @@ void interpose() {
370370
assertEquals(
371371
"[0, 500, 1, 500, 2, 500, 3]",
372372
Underscore.interpose(Underscore.range(4), 500).toString());
373-
assertEquals("[]", Underscore.interpose(new ArrayList<Integer>(), 500).toString());
374-
assertEquals("[]", Underscore.interpose(new ArrayList<Object>(), null).toString());
373+
assertEquals("[]", Underscore.interpose(new ArrayList<>(), 500).toString());
374+
assertEquals("[]", Underscore.interpose(new ArrayList<>(), null).toString());
375375
assertEquals(
376376
"[0, 1, 2, 3]",
377377
Underscore.interpose(Underscore.newArrayList(Underscore.range(4)), null)
@@ -384,7 +384,7 @@ void interpose() {
384384
assertEquals("[a, b]", new Underscore<>(singletonList("a, b")).interpose(null).toString());
385385
assertEquals("[a]", Underscore.chain(singletonList("a")).interpose("interpose").toString());
386386
assertEquals(
387-
"[]", Underscore.chain(new ArrayList<Object>()).interpose("interpose").toString());
387+
"[]", Underscore.chain(new ArrayList<>()).interpose("interpose").toString());
388388
assertEquals(
389389
"[a, b, c]", Underscore.chain(asList("a", "b", "c")).interpose(null).toString());
390390
assertEquals(
@@ -771,7 +771,7 @@ public String toString() {
771771
}
772772
}
773773
final int result =
774-
Underscore.<Person>sortedIndex(
774+
Underscore.sortedIndex(
775775
asList(
776776
new Person("moe", 40),
777777
new Person("moe", 50),
@@ -780,7 +780,7 @@ public String toString() {
780780
"age");
781781
assertEquals(1, result);
782782
final int result2 =
783-
Underscore.<Person>sortedIndex(
783+
Underscore.sortedIndex(
784784
asList(
785785
new Person("moe", 40),
786786
new Person("moe", 50),
@@ -789,7 +789,7 @@ public String toString() {
789789
"age");
790790
assertEquals(-1, result2);
791791
final int resultArray =
792-
Underscore.<Person>sortedIndex(
792+
Underscore.sortedIndex(
793793
new Person[] {
794794
new Person("moe", 40), new Person("moe", 50), new Person("curly", 60)
795795
},

src/test/java/com/github/underscore/CollectionsTest.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1677,8 +1677,7 @@ public Integer next() {
16771677
}
16781678

16791679
@Override
1680-
public void remove() {
1681-
}
1680+
public void remove() {}
16821681
};
16831682
assertEquals(6, Underscore.size(iterable));
16841683
assertEquals(5, Underscore.size(new Integer[] {5, 4, 3, 2, 1}));

src/test/java/com/github/underscore/FunctionsTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ void defer() {
199199
return null;
200200
});
201201
assertEquals(0, counter[0].intValue(), "incr was debounced");
202-
await().atMost(240, TimeUnit.MILLISECONDS)
202+
await().atMost(400, TimeUnit.MILLISECONDS)
203203
.until(
204204
() -> {
205205
assertEquals(1, counter[0].intValue(), "incr was debounced");

0 commit comments

Comments
 (0)