Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add special support for enum values #5441

Merged
merged 1 commit into from
Jun 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
Expand Down Expand Up @@ -124,81 +123,15 @@ public void serialize(Object value, String type, Limits limits) throws Exception
if (value == null) {
tokenWriter.nullValue();
} else if (isPrimitive(type) || WellKnownClasses.isToStringSafe(type)) {
if (value instanceof String) {
String strValue = (String) value;
int originalLength = strValue.length();
boolean isComplete = true;
if (originalLength > limits.maxLength) {
strValue = strValue.substring(0, limits.maxLength);
isComplete = false;
}
tokenWriter.string(strValue, isComplete, originalLength);
} else {
tokenWriter.primitiveValue(value);
}
serializePrimitive(value, limits);
} else if (value.getClass().isArray() && (limits.maxReferenceDepth > 0)) {
int arraySize = Array.getLength(value);
boolean isComplete = true;
tokenWriter.arrayPrologue(value);
if (value.getClass().getComponentType().isPrimitive()) {
Class<?> componentType = value.getClass().getComponentType();
if (componentType == long.class) {
isComplete = serializeLongArray((long[]) value, limits.maxCollectionSize);
}
if (componentType == int.class) {
isComplete = serializeIntArray((int[]) value, limits.maxCollectionSize);
}
if (componentType == short.class) {
isComplete = serializeShortArray((short[]) value, limits.maxCollectionSize);
}
if (componentType == char.class) {
isComplete = serializeCharArray((char[]) value, limits.maxCollectionSize);
}
if (componentType == byte.class) {
isComplete = serializeByteArray((byte[]) value, limits.maxCollectionSize);
}
if (componentType == boolean.class) {
isComplete = serializeBooleanArray((boolean[]) value, limits.maxCollectionSize);
}
if (componentType == float.class) {
isComplete = serializeFloatArray((float[]) value, limits.maxCollectionSize);
}
if (componentType == double.class) {
isComplete = serializeDoubleArray((double[]) value, limits.maxCollectionSize);
}
} else {
isComplete = serializeObjectArray((Object[]) value, limits);
}
tokenWriter.arrayEpilogue(value, isComplete, arraySize);
serializeArray(value, limits);
} else if (value instanceof Collection && (limits.maxReferenceDepth > 0)) {
tokenWriter.collectionPrologue(value);
Collection<?> col;
boolean isComplete = true;
int size = 0;
try {
col = (Collection<?>) value;
size = col.size(); // /!\ alien call /!\
isComplete = serializeCollection(col, limits); // /!\ contains alien calls /!\
tokenWriter.collectionEpilogue(value, isComplete, size);
} catch (Exception ex) {
tokenWriter.collectionEpilogue(value, isComplete, size);
tokenWriter.notCaptured(ex.toString());
}
serializeCollection(value, limits);
} else if (value instanceof Map && (limits.maxReferenceDepth > 0)) {
tokenWriter.mapPrologue(value);
Map<?, ?> map = Collections.emptyMap();
boolean isComplete = true;
int size = 0;
try {
map = (Map<?, ?>) value;
size = map.size(); // /!\ alien call /!\
Set<? extends Map.Entry<?, ?>> entries = map.entrySet(); // /!\ alien call /!\
isComplete = serializeMap(entries, limits); // /!\ contains alien calls /!\
tokenWriter.mapEpilogue(isComplete, size);
} catch (Exception ex) {
tokenWriter.mapEpilogue(isComplete, size);
tokenWriter.notCaptured(ex.toString());
}
serializeMap(value, limits);
} else if (value instanceof Enum) {
serializeEnum(value, limits);
} else if (limits.maxReferenceDepth > 0) {
serializeObjectValue(value, limits);
} else {
Expand All @@ -207,6 +140,95 @@ public void serialize(Object value, String type, Limits limits) throws Exception
tokenWriter.epilogue(value);
}

private void serializeEnum(Object value, Limits limits) throws Exception {
Enum<?> enumValue = (Enum<?>) value;
serializePrimitive(enumValue.name(), limits);
}

private void serializeMap(Object value, Limits limits) throws Exception {
tokenWriter.mapPrologue(value);
Map<?, ?> map;
boolean isComplete = true;
int size = 0;
try {
map = (Map<?, ?>) value;
size = map.size(); // /!\ alien call /!\
Set<? extends Map.Entry<?, ?>> entries = map.entrySet(); // /!\ alien call /!\
isComplete = serializeMapEntries(entries, limits); // /!\ contains alien calls /!\
tokenWriter.mapEpilogue(isComplete, size);
} catch (Exception ex) {
tokenWriter.mapEpilogue(isComplete, size);
tokenWriter.notCaptured(ex.toString());
}
}

private void serializeCollection(Object value, Limits limits) throws Exception {
tokenWriter.collectionPrologue(value);
Collection<?> col;
boolean isComplete = true;
int size = 0;
try {
col = (Collection<?>) value;
size = col.size(); // /!\ alien call /!\
isComplete = serializeCollection(col, limits); // /!\ contains alien calls /!\
tokenWriter.collectionEpilogue(value, isComplete, size);
} catch (Exception ex) {
tokenWriter.collectionEpilogue(value, isComplete, size);
tokenWriter.notCaptured(ex.toString());
}
}

private void serializeArray(Object value, Limits limits) throws Exception {
int arraySize = Array.getLength(value);
boolean isComplete = true;
tokenWriter.arrayPrologue(value);
if (value.getClass().getComponentType().isPrimitive()) {
Class<?> componentType = value.getClass().getComponentType();
if (componentType == long.class) {
isComplete = serializeLongArray((long[]) value, limits.maxCollectionSize);
}
if (componentType == int.class) {
isComplete = serializeIntArray((int[]) value, limits.maxCollectionSize);
}
if (componentType == short.class) {
isComplete = serializeShortArray((short[]) value, limits.maxCollectionSize);
}
if (componentType == char.class) {
isComplete = serializeCharArray((char[]) value, limits.maxCollectionSize);
}
if (componentType == byte.class) {
isComplete = serializeByteArray((byte[]) value, limits.maxCollectionSize);
}
if (componentType == boolean.class) {
isComplete = serializeBooleanArray((boolean[]) value, limits.maxCollectionSize);
}
if (componentType == float.class) {
isComplete = serializeFloatArray((float[]) value, limits.maxCollectionSize);
}
if (componentType == double.class) {
isComplete = serializeDoubleArray((double[]) value, limits.maxCollectionSize);
}
} else {
isComplete = serializeObjectArray((Object[]) value, limits);
}
tokenWriter.arrayEpilogue(value, isComplete, arraySize);
}

private void serializePrimitive(Object value, Limits limits) throws Exception {
if (value instanceof String) {
String strValue = (String) value;
int originalLength = strValue.length();
boolean isComplete = true;
if (originalLength > limits.maxLength) {
strValue = strValue.substring(0, limits.maxLength);
isComplete = false;
}
tokenWriter.string(strValue, isComplete, originalLength);
} else {
tokenWriter.primitiveValue(value);
}
}

private void serializeObjectValue(Object value, Limits limits) throws Exception {
tokenWriter.objectPrologue(value);
Class<?> currentClass = value.getClass();
Expand Down Expand Up @@ -381,7 +403,7 @@ private boolean serializeCollection(Collection<?> collection, Limits limits) thr
return maxSize == colSize;
}

private boolean serializeMap(Set<? extends Map.Entry<?, ?>> entries, Limits limits)
private boolean serializeMapEntries(Set<? extends Map.Entry<?, ?>> entries, Limits limits)
throws Exception {
int mapSize = entries.size(); // /!\ alien call /!\
int maxSize = Math.min(mapSize, limits.maxCollectionSize);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1387,7 +1387,7 @@ public void enumConstructorArgs() throws IOException, URISyntaxException {
DebuggerTransformerTest.TestSnapshotListener listener =
installProbes(ENUM_CLASS, createProbe(PROBE_ID, ENUM_CLASS, "<init>", null));
Class<?> testClass = compileAndLoadClass(CLASS_NAME);
int result = Reflect.on(testClass).call("main", "2").get();
int result = Reflect.on(testClass).call("main", "").get();
Assertions.assertEquals(2, result);
assertSnapshots(listener, 3, PROBE_ID);
Map<String, CapturedContext.CapturedValue> arguments =
Expand All @@ -1398,6 +1398,21 @@ public void enumConstructorArgs() throws IOException, URISyntaxException {
assertTrue(arguments.containsKey("strValue"));
}

@Test
public void enumValues() throws IOException, URISyntaxException {
final String CLASS_NAME = "com.datadog.debugger.CapturedSnapshot23";
DebuggerTransformerTest.TestSnapshotListener listener =
installProbes(CLASS_NAME, createProbe(PROBE_ID, CLASS_NAME, "convert", null));
Class<?> testClass = compileAndLoadClass(CLASS_NAME);
int result = Reflect.on(testClass).call("main", "2").get();
Assertions.assertEquals(2, result);
Snapshot snapshot = assertOneSnapshot(listener);
assertCaptureReturnValue(
snapshot.getCaptures().getReturn(),
"com.datadog.debugger.CapturedSnapshot23$MyEnum",
"TWO");
}

@Test
public void recursiveCapture() throws IOException, URISyntaxException {
final String CLASS_NAME = "com.datadog.debugger.CapturedSnapshot24";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -843,6 +843,28 @@ public void valueTimeout() throws IOException {
Assertions.assertEquals(TIMEOUT_REASON, json.get(NOT_CAPTURED_REASON));
}

enum MyEnum {
ONE,
TWO,
THREE;
}

@Test
public void enumValues() throws IOException {
JsonAdapter<Snapshot> adapter = createSnapshotAdapter();
Snapshot snapshot = createSnapshot();
CapturedContext context = new CapturedContext();
CapturedContext.CapturedValue enumValue =
CapturedContext.CapturedValue.of("enumValue", MyEnum.class.getTypeName(), MyEnum.TWO);
context.addLocals(new CapturedContext.CapturedValue[] {enumValue});
snapshot.setExit(context);
String buffer = adapter.toJson(snapshot);
System.out.println(buffer);
Map<String, Object> locals = getLocalsFromJson(buffer);
Map<String, Object> enumValueJson = (Map<String, Object>) locals.get("enumValue");
assertEquals("TWO", enumValueJson.get("value"));
}

private Map<String, Object> doFieldCount(int maxFieldCount) throws IOException {
JsonAdapter<Snapshot> adapter = createSnapshotAdapter();
Snapshot snapshot = createSnapshotForFieldCount(maxFieldCount);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -448,7 +448,7 @@ private static Object convertPrimitive(String strValue, String type) {
case "java.lang.String":
return strValue;
}
return null;
return strValue;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,20 @@ public String getStrValue() {
}

private int doit(String arg) {
return Integer.parseInt(MyEnum.TWO.getStrValue());
if ("".equals(arg)) {
return Integer.parseInt(MyEnum.TWO.getStrValue());
}
return Integer.parseInt(convert(arg).getStrValue());
}

private MyEnum convert(String value) {
switch (value) {
case "1": return MyEnum.ONE;
case "2": return MyEnum.TWO;
case "3": return MyEnum.THREE;
default:
throw new IllegalArgumentException("Unknown value: " + value);
}
}

public static int main(String arg) {
Expand Down