DataFixerUpper icon indicating copy to clipboard operation
DataFixerUpper copied to clipboard

JsonOps.convertTo explodes on JsonNulls

Open quat1024 opened this issue 3 years ago • 1 comments

public static void main(String[] args) {
	JsonObject j = new JsonObject();
	j.add("test", JsonNull.INSTANCE);
	
	System.out.println(JsonOps.INSTANCE.convertTo(JsonOps.INSTANCE, j)); //should return a copy of `j`
}

fails with

Exception in thread "main" java.lang.NullPointerException: Cannot invoke "com.google.gson.JsonElement.getAsJsonPrimitive()" because "input" is null
	at com.mojang.serialization.JsonOps.convertTo(JsonOps.java:50)
	at com.mojang.serialization.JsonOps.convertTo(JsonOps.java:24)
	at com.mojang.serialization.DynamicOps.lambda$convertMap$27(DynamicOps.java:255)
	at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197)
	at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197)
	at java.base/java.util.Iterator.forEachRemaining(Iterator.java:133)
	at java.base/java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1845)
	at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509)
	at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
	at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150)
	at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173)
	at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
	at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:596)
	at com.mojang.serialization.JsonOps.createMap(JsonOps.java:275)
	at com.mojang.serialization.JsonOps.createMap(JsonOps.java:24)
	at com.mojang.serialization.DynamicOps.convertMap(DynamicOps.java:254)
	at com.mojang.serialization.JsonOps.convertTo(JsonOps.java:42)
	at agency.highlysuspect.apathy.rule.CodecUtil.main(CodecUtil.java:145)

It appears there is a check for instanceof JsonNulls: https://github.com/Mojang/DataFixerUpper/blob/c100ef03c2ab321e5de4f25ffbe277e924aa7ca5/src/main/java/com/mojang/serialization/JsonOps.java#L47-L50

But it doesn't work, because DynamicOps#getJsonValues, as well as other methods like getStream and getList, filter JsonNulls to actual nulls. https://github.com/Mojang/DataFixerUpper/blob/c100ef03c2ab321e5de4f25ffbe277e924aa7ca5/src/main/java/com/mojang/serialization/JsonOps.java#L218

quat1024 avatar Apr 11 '22 22:04 quat1024

The workaround i'm using in my current project (making a Codec out of something that has toJson and fromJson methods, where toJson sometimes returns JsonObjects containing JsonNulls) is just preprocessing the entire JsonObject and filtering out nulls in objects/arrays, which isn't strictly correct because it loses the distinction between "key present with null value" and "absent key", but in practice it tends to work for what im using it for

quat1024 avatar Apr 11 '22 22:04 quat1024