Initial commit

This commit is contained in:
Alan Bateman 2026-03-27 08:26:40 +00:00
parent 60ce4857f4
commit 6000b3fd6b
9 changed files with 204 additions and 149 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -469,8 +469,14 @@ public class ThreadDumper {
writer.print("\"" + name + "\": ");
}
switch (obj) {
// Long may be larger than safe range of JSON integer value
case Long _ -> writer.print("\"" + obj + "\"");
case Long value -> {
// write as string for interop when outside +/- 2^531
if (value < -0x1FFFFFFFFFFFFFL || value > 0x1FFFFFFFFFFFFFL) {
writer.print("\"" + value + "\"");
} else {
writer.print(value);
}
}
case Number _ -> writer.print(obj);
case Boolean _ -> writer.print(obj);
case null -> writer.print("null");

View File

@ -5,7 +5,7 @@
"type": "object",
"properties": {
"processId": {
"type": "string",
"type": [ "integer", "string" ],
"description": "The native process id of the Java virtual machine."
},
"time": {
@ -28,17 +28,11 @@
"description": "The container name. The container name is unique."
},
"parent": {
"type": [
"string",
"null"
],
"type": [ "string", "null" ],
"description": "The parent container name or null for the root container."
},
"owner": {
"type": [
"string",
"null"
],
"type": [ "integer", "string", "null" ],
"description": "The thread identifier of the owner thread if owned."
},
"threads": {
@ -49,7 +43,7 @@
"type": "object",
"properties": {
"tid": {
"type": "string",
"type": [ "integer", "string" ],
"description": "The thread identifier."
},
"time": {
@ -69,9 +63,7 @@
"description": "true for a virtual thread."
},
"parkBlocker": {
"type": [
"object"
],
"type": "object",
"properties": {
"object": {
"type": "string",
@ -79,7 +71,7 @@
}
},
"owner": {
"type": "string",
"type": [ "integer", "string" ],
"description": "The thread identifier of the owner when the parkBlocker is an AbstractOwnableSynchronizer."
},
"required": [
@ -132,7 +124,7 @@
}
},
"carrier": {
"type": "string",
"type": [ "integer", "string" ],
"description": "The thread identifier of the carrier thread if mounted."
}
},
@ -147,7 +139,7 @@
]
},
"threadCount": {
"type": "string",
"type": "integer",
"description": "The number of threads in the thread container."
}
},

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -82,12 +82,12 @@ public class KAT9180 {
var c1 = Cipher.getInstance("HPKE");
var c2 = Cipher.getInstance("HPKE");
var ts = JSONValue.parse(new String(Files.readAllBytes(archivePath), StandardCharsets.UTF_8));
for (var tg : ts.asArray()) {
var mode = Integer.parseInt(tg.get("mode").asString());
for (var tg : ts.elements()) {
var mode = tg.get("mode").asInt();
System.err.print('I');
var kem_id = Integer.parseInt(tg.get("kem_id").asString());
var kdf_id = Integer.parseInt(tg.get("kdf_id").asString());
var aead_id = Integer.parseInt(tg.get("aead_id").asString());
var kem_id = tg.get("kem_id").asInt();
var kdf_id = tg.get("kdf_id").asInt();
var aead_id = tg.get("aead_id").asInt();
var ikmR = h.parseHex(tg.get("ikmR").asString());
var ikmE = h.parseHex(tg.get("ikmE").asString());
var info = h.parseHex(tg.get("info").asString());
@ -117,7 +117,7 @@ public class KAT9180 {
if (enc != null) {
System.err.print('e');
var count = 0;
for (var p : enc.asArray()) {
for (var p : enc.elements()) {
var aad = h.parseHex(p.get("aad").asString());
var pt = h.parseHex(p.get("pt").asString());
var ct = h.parseHex(p.get("ct").asString());

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -28,6 +28,7 @@ import java.time.OffsetDateTime;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import jdk.jfr.Timespan;
import jdk.jfr.Timestamp;
@ -62,7 +63,7 @@ public class TestPrintJSON {
JSONValue o = JSONValue.parse(json);
JSONValue recording = o.get("recording");
JSONArray jsonEvents = recording.get("events").asArray();
List<JSONValue> jsonEvents = recording.get("events").elements();
List<RecordedEvent> events = RecordingFile.readAllEvents(recordingFile);
Collections.sort(events, new EndTicksComparator());
// Verify events are equal
@ -79,7 +80,7 @@ public class TestPrintJSON {
private static void assertEquals(Object jsonObject, Object jfrObject) throws Exception {
// Check object
if (jfrObject instanceof RecordedObject) {
JSONValue values = ((JSONValue) jsonObject).get("values");
Map<String, JSONValue> values = ((JSONValue) jsonObject).get("values").members();
RecordedObject recObject = (RecordedObject) jfrObject;
Asserts.assertEquals(values.size(), recObject.getFields().size());
for (ValueDescriptor v : recObject.getFields()) {
@ -102,7 +103,7 @@ public class TestPrintJSON {
// Check array
if (jfrObject != null && jfrObject.getClass().isArray()) {
Object[] jfrArray = (Object[]) jfrObject;
JSONArray jsArray = ((JSONArray) jsonObject);
List<JSONValue> jsArray = ((JSONValue) jsonObject).elements();
for (int i = 0; i < jfrArray.length; i++) {
assertEquals(jsArray.get(i), jfrArray[i]);
}

View File

@ -63,12 +63,12 @@ public class ML_DSA_Test {
var f = p == null
? KeyFactory.getInstance("ML-DSA")
: KeyFactory.getInstance("ML-DSA", p);
for (var t : kat.get("testGroups").asArray()) {
for (var t : kat.get("testGroups").elements()) {
var pname = t.get("parameterSet").asString();
var np = genParams(pname);
System.out.println(">> " + pname);
for (var c : t.get("tests").asArray()) {
System.out.print(c.get("tcId").asString() + " ");
for (var c : t.get("tests").elements()) {
System.out.print(c.get("tcId").asInt() + " ");
var seed = toByteArray(c.get("seed").asString());
g.initialize(np, new FixedSecureRandom(seed));
var kp = g.generateKeyPair();
@ -85,7 +85,7 @@ public class ML_DSA_Test {
var s = p == null
? Signature.getInstance("ML-DSA")
: Signature.getInstance("ML-DSA", p);
for (var t : kat.get("testGroups").asArray()) {
for (var t : kat.get("testGroups").elements()) {
var pname = t.get("parameterSet").asString();
System.out.println(">> " + pname + " sign");
var det = t.get("deterministic").asBoolean();
@ -97,14 +97,14 @@ public class ML_DSA_Test {
if (t.get("externalMu").asBoolean()) {
continue; // Not supported
}
for (var c : t.get("tests").asArray()) {
var cstr = c.get("context");
for (var c : t.get("tests").elements()) {
var cstr = c.getOrAbsent("context").orElse(null);
var ctxt = cstr == null ? new byte[0] : toByteArray(cstr.asString());
var hashAlg = c.get("hashAlg").asString();
if (!hashAlg.equals("none") || ctxt.length != 0) {
continue; // Not supported
}
System.out.print(Integer.parseInt(c.get("tcId").asString()) + " ");
System.out.print(c.get("tcId").asInt() + " ");
var sk = new PrivateKey() {
public String getAlgorithm() { return pname; }
public String getFormat() { return "RAW"; }
@ -129,7 +129,7 @@ public class ML_DSA_Test {
var s = p == null
? Signature.getInstance("ML-DSA")
: Signature.getInstance("ML-DSA", p);
for (var t : kat.get("testGroups").asArray()) {
for (var t : kat.get("testGroups").elements()) {
var pname = t.get("parameterSet").asString();
System.out.println(">> " + pname + " verify");
@ -143,14 +143,14 @@ public class ML_DSA_Test {
continue; // Not supported
}
for (var c : t.get("tests").asArray()) {
var cstr = c.get("context");
for (var c : t.get("tests").elements()) {
var cstr = c.getOrAbsent("context").orElse(null);
var ctxt = cstr == null ? new byte[0] : toByteArray(cstr.asString());
var hashAlg = c.get("hashAlg").asString();
if (!hashAlg.equals("none") || ctxt.length != 0) {
continue; // Not supported
}
System.out.print(c.get("tcId").asString() + " ");
System.out.print(c.get("tcId").asInt() + " ");
var pk = new PublicKey() {
public String getAlgorithm() { return pname; }
public String getFormat() { return "RAW"; }

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -61,12 +61,12 @@ public class ML_KEM_Test {
var f = p == null
? KeyFactory.getInstance("ML-KEM")
: KeyFactory.getInstance("ML-KEM", p);
for (var t : kat.get("testGroups").asArray()) {
for (var t : kat.get("testGroups").elements()) {
var pname = t.get("parameterSet").asString();
var np = genParams(pname);
System.out.println(">> " + pname);
for (var c : t.get("tests").asArray()) {
System.out.print(c.get("tcId").asString() + " ");
for (var c : t.get("tests").elements()) {
System.out.print(c.get("tcId").asInt() + " ");
var seed = toByteArray(c.get("d").asString() + c.get("z").asString());
g.initialize(np, new FixedSecureRandom(seed));
var kp = g.generateKeyPair();
@ -84,13 +84,13 @@ public class ML_KEM_Test {
var g = p == null
? KEM.getInstance("ML-KEM")
: KEM.getInstance("ML-KEM", p);
for (var t : kat.get("testGroups").asArray()) {
for (var t : kat.get("testGroups").elements()) {
var pname = t.get("parameterSet").asString();
var function = t.get("function").asString();
System.out.println(">> " + pname + " " + function);
if (function.equals("encapsulation")) {
for (var c : t.get("tests").asArray()) {
System.out.print(c.get("tcId").asString() + " ");
for (var c : t.get("tests").elements()) {
System.out.print(c.get("tcId").asInt() + " ");
var ek = new PublicKey() {
public String getAlgorithm() { return pname; }
public String getFormat() { return "RAW"; }
@ -111,8 +111,8 @@ public class ML_KEM_Test {
public String getFormat() { return "RAW"; }
public byte[] getEncoded() { return oct(toByteArray(t.get("dk").asString())); }
};
for (var c : t.get("tests").asArray()) {
System.out.print(c.get("tcId").asString() + " ");
for (var c : t.get("tests").elements()) {
System.out.print(c.get("tcId").asInt() + " ");
var d = g.newDecapsulator(dk);
var k = d.decapsulate(toByteArray(c.get("c").asString()));
Asserts.assertEqualsByteArray(toByteArray(c.get("k").asString()), k.getEncoded());

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -37,14 +37,14 @@ public class SHA_Test {
if (alg.startsWith("SHA2-")) alg = "SHA-" + alg.substring(5);
var md = provider == null ? MessageDigest.getInstance(alg)
: MessageDigest.getInstance(alg, provider);
for (var t : kat.get("testGroups").asArray()) {
for (var t : kat.get("testGroups").elements()) {
var testType = t.get("testType").asString();
switch (testType) {
case "AFT" -> {
for (var c : t.get("tests").asArray()) {
System.out.print(c.get("tcId").asString() + " ");
for (var c : t.get("tests").elements()) {
System.out.print(c.get("tcId").asInt() + " ");
var msg = toByteArray(c.get("msg").asString());
var len = Integer.parseInt(c.get("len").asString());
var len = c.get("len").asInt();
if (msg.length * 8 == len) {
Asserts.assertEqualsByteArray(
toByteArray(c.get("md").asString()), md.digest(msg));
@ -56,12 +56,12 @@ public class SHA_Test {
case "MCT" -> {
var mctVersion = t.get("mctVersion").asString();
var trunc = mctVersion.equals("alternate");
for (var c : t.get("tests").asArray()) {
System.out.print(c.get("tcId").asString() + " ");
for (var c : t.get("tests").elements()) {
System.out.print(c.get("tcId").asInt() + " ");
var SEED = toByteArray(c.get("msg").asString());
var INITIAL_SEED_LENGTH = Integer.parseInt(c.get("len").asString());
var INITIAL_SEED_LENGTH = c.get("len").asInt();
if (SEED.length * 8 == INITIAL_SEED_LENGTH) {
for (var r : c.get("resultsArray").asArray()) {
for (var r : c.get("resultsArray").elements()) {
if (alg.startsWith("SHA3-")) {
var MD = SEED;
for (var i = 0; i < 1000; i++) {
@ -99,12 +99,12 @@ public class SHA_Test {
}
}
case "LDT" -> {
for (var c : t.get("tests").asArray()) {
System.out.print(c.get("tcId").asString() + " ");
for (var c : t.get("tests").elements()) {
System.out.print(c.get("tcId").asInt() + " ");
var lm = c.get("largeMsg");
var ct = toByteArray(lm.get("content").asString());
var flen = Long.parseLong(lm.get("fullLength").asString());
var clen = Long.parseLong(lm.get("contentLength").asString());
var flen = lm.get("fullLength").asLong();
var clen = lm.get("contentLength").asLong();
var cc = 0L;
while (cc < flen) {
md.update(ct);

View File

@ -25,47 +25,55 @@ package jdk.test.lib.json;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Optional;
public interface JSONValue {
public sealed interface JSONValue
permits JSONValue.JSONObject, JSONValue.JSONArray, JSONValue.JSONString,
JSONValue.JSONNumber, JSONValue.JSONBoolean, JSONValue.JSONNull {
public final class JSONObject implements JSONValue {
private final Map<String, JSONValue> value;
private final Map<String, JSONValue> members;
public JSONObject(Map<String, JSONValue> value) {
this.value = value;
private JSONObject(Map<String, ? extends JSONValue> members) {
this.members = Map.copyOf(members);
}
@Override
public JSONObject asObject() {
return this;
}
public JSONValue get(String k) {
return value.get(k);
public JSONValue get(String name) {
JSONValue v = members.get(name);
if (v == null) {
throw new NoSuchElementException("member " + name + " does not exist");
}
return v;
}
@Override
public int size() {
return value.size();
public Optional<JSONValue> getOrAbsent(String name) {
return Optional.ofNullable(members.get(name));
}
@Override
public Map<String, JSONValue> members() {
return members;
}
@Override
public String toString() {
var builder = new StringBuilder();
builder.append("{");
for (var key : value.keySet()) {
for (String key : members.keySet()) {
builder.append("\"");
builder.append(key);
builder.append("\":");
builder.append(value.get(key).toString());
builder.append(members.get(key).toString());
builder.append(",");
}
var end = builder.length() - 1;
int end = builder.length() - 1;
if (builder.charAt(end) == ',') {
builder.deleteCharAt(end);
}
@ -73,13 +81,17 @@ public interface JSONValue {
builder.append("}");
return builder.toString();
}
public static JSONObject of(Map<String, ? extends JSONValue> members) {
return new JSONObject(members);
}
}
public final class JSONString implements JSONValue {
private final String value;
public JSONString(String value) {
this.value = value;
private JSONString(String value) {
this.value = Objects.requireNonNull(value);
}
@Override
@ -129,26 +141,17 @@ public interface JSONValue {
builder.append("\"");
return builder.toString();
}
public static JSONString of(String value) {
return new JSONString(value);
}
}
public final class JSONArray implements JSONValue, Iterable<JSONValue> {
private final List<JSONValue> values;
public final class JSONArray implements JSONValue {
private final List<JSONValue> elements;
public JSONArray(List<JSONValue> array) {
this.values = array;
}
@Override
public JSONArray asArray() {
return this;
}
public JSONValue get(int i) {
return values.get(i);
}
public int size() {
return values.size();
JSONArray(List<? extends JSONValue> elements) {
this.elements = List.copyOf(elements);
}
@Override
@ -156,9 +159,10 @@ public interface JSONValue {
var builder = new StringBuilder();
builder.append("[");
for (var i = 0; i < size(); i++) {
builder.append(get(i).toString());
if (i != (size() - 1)) {
int size = elements.size();
for (int i = 0; i < size; i++) {
builder.append(elements.get(i).toString());
if (i != (size - 1)) {
builder.append(",");
}
}
@ -167,13 +171,61 @@ public interface JSONValue {
}
@Override
public Iterator<JSONValue> iterator() {
return values.iterator();
public List<JSONValue> elements() {
return elements;
}
@Override
public List<JSONValue> elements() {
return List.copyOf(values);
public JSONValue element(int index) {
return elements.get(index);
}
public static JSONArray of(List<? extends JSONValue> elements) {
return new JSONArray(elements);
}
}
public final class JSONNumber implements JSONValue {
private final String value;
private JSONNumber(String value) {
this.value = Objects.requireNonNull(value);
}
@Override
public int asInt() {
return Integer.parseInt(value);
}
@Override
public long asLong() {
return Long.parseLong(value);
}
@Override
public double asDouble() {
return Double.parseDouble(value);
}
@Override
public String toString() {
return value;
}
public static JSONNumber of(String value) {
return new JSONNumber(value);
}
public static JSONNumber of(int value) {
return of(String.valueOf(value));
}
public static JSONNumber of(long value) {
return of(String.valueOf(value));
}
public static JSONNumber of(double value) {
return of(String.valueOf(value));
}
}
@ -367,11 +419,10 @@ public interface JSONValue {
var value = builder.toString();
if (isInteger) {
new BigInteger(value);
return new JSONString(value);
} else {
Double.parseDouble(value);
return new JSONString(value);
}
return JSONNumber.of(value);
}
private JSONString parseString() {
@ -422,7 +473,7 @@ public interface JSONValue {
}
advance(); // step beyond closing "
return new JSONString(builder.toString());
return JSONString.of(builder.toString());
}
private JSONArray parseArray() {
@ -445,7 +496,7 @@ public interface JSONValue {
}
advance(); // step beyond closing ']'
return new JSONArray(list);
return JSONArray.of(list);
}
public JSONNull parseNull() {
@ -486,7 +537,7 @@ public interface JSONValue {
}
advance(); // step beyond '}'
return new JSONObject(map);
return JSONObject.of(map);
}
private boolean isDigit(char c) {
@ -574,43 +625,51 @@ public interface JSONValue {
}
}
public static JSONValue parse(String s) {
static JSONValue parse(String s) {
return new JSONParser().parse(s);
}
default int size() {
throw new UnsupportedOperationException("Size operation unsupported");
default JSONValue get(String name) {
throw new UnsupportedOperationException("Unsupported conversion to object");
}
default Optional<JSONValue> getOrAbsent(String name) {
throw new UnsupportedOperationException("Unsupported conversion to object");
}
default Optional<JSONValue> valueOrNull() {
return Optional.of(this);
}
default Map<String, JSONValue> members() {
throw new UnsupportedOperationException("Unsupported conversion to object");
}
default List<JSONValue> elements() {
throw new UnsupportedOperationException("Unsupported conversion to array");
}
default String asString() {
throw new UnsupportedOperationException("Unsupported conversion to String");
}
default JSONArray asArray() {
default JSONValue element(int index) {
throw new UnsupportedOperationException("Unsupported conversion to array");
}
default JSONObject asObject() {
throw new UnsupportedOperationException("Unsupported conversion to object");
default String asString() {
throw new UnsupportedOperationException("Unsupported conversion to string");
}
default int asInt() {
throw new UnsupportedOperationException("Unsupported conversion to number");
}
default long asLong() {
throw new UnsupportedOperationException("Unsupported conversion to number");
}
default double asDouble() {
throw new UnsupportedOperationException("Unsupported conversion to number");
}
default boolean asBoolean() {
throw new UnsupportedOperationException("Unsupported conversion to boolean");
}
default JSONValue get(String field) {
return asObject().get(field);
}
default Optional<JSONValue> getOrAbsent(String field) {
return Optional.ofNullable(get(field));
}
default Optional<JSONValue> valueOrNull() {
return Optional.of(this);
}
}

View File

@ -132,17 +132,14 @@ public final class ThreadDump {
}
/**
* Assert that a JSONValue is a JSONString and parse the string as an int.
* Convert the given JSON value (number or string) to a long.
*/
private static int parseStringAsInt(JSONValue valueObj) {
return Integer.parseInt(valueObj.asString());
}
/**
* Assert that a JSONValue is a JSONString and parse the string as a long.
*/
private static long parseStringAsLong(JSONValue valueObj) {
return Long.parseLong(valueObj.asString());
private static long toLong(JSONValue value) {
return switch (value) {
case JSONValue.JSONNumber _ -> value.asLong();
case JSONValue.JSONString _ -> Long.parseLong(value.asString());
default -> throw new RuntimeException("Not number or string");
};
}
/**
@ -178,9 +175,9 @@ public final class ThreadDump {
* Return the thread identifier of the owner or empty OptionalLong if not owned.
*/
public OptionalLong owner() {
return containerObj.get("owner") // string or null
return containerObj.get("owner") // number or string or null
.valueOrNull()
.map(v -> OptionalLong.of(parseStringAsLong(v)))
.map(v -> OptionalLong.of(toLong(v)))
.orElse(OptionalLong.empty());
}
@ -245,7 +242,7 @@ public final class ThreadDump {
private final JSONValue threadObj;
ThreadInfo(JSONValue threadObj) {
this.tid = parseStringAsLong(threadObj.get("tid"));
this.tid = toLong(threadObj.get("tid"));
this.threadObj = threadObj;
}
@ -293,7 +290,7 @@ public final class ThreadDump {
*/
public OptionalLong parkBlockerOwner() {
return threadObj.getOrAbsent("parkBlocker")
.map(v -> OptionalLong.of(parseStringAsLong(v.get("owner"))))
.map(v -> OptionalLong.of(toLong(v.get("owner"))))
.orElse(OptionalLong.empty());
}
@ -334,7 +331,7 @@ public final class ThreadDump {
.map(JSONValue::elements)
.orElse(List.of())
.forEach(e -> {
int depth = parseStringAsInt(e.get("depth"));
int depth = e.get("depth").asInt();
List<String> locks = e.get("locks")
.elements()
.stream()
@ -354,7 +351,7 @@ public final class ThreadDump {
*/
public OptionalLong carrier() {
return threadObj.getOrAbsent("carrier")
.map(s -> OptionalLong.of(parseStringAsLong(s)))
.map(v -> OptionalLong.of(toLong(v)))
.orElse(OptionalLong.empty());
}
@ -389,7 +386,7 @@ public final class ThreadDump {
* Returns the value of threadDump/processId.
*/
public long processId() {
return parseStringAsLong(threadDumpObj.get("processId"));
return toLong(threadDumpObj.get("processId"));
}
/**