Skip to content

Commit

Permalink
#738 added support for typeLiterals in json wire (#795)
Browse files Browse the repository at this point in the history
* #738 added support for typeLiterals

* #738 tests failures fixed

* #738 tests failures fixed

* #738 fixed based on Yevgens feedback

---------

Co-authored-by: Rob Austin <rob.austin@boundedbuffer.co.uk>
  • Loading branch information
RobAustin and Rob Austin authored Dec 28, 2023
1 parent 10e4237 commit 3a27cf7
Show file tree
Hide file tree
Showing 2 changed files with 117 additions and 10 deletions.
98 changes: 89 additions & 9 deletions src/main/java/net/openhft/chronicle/wire/JSONWire.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import net.openhft.chronicle.core.io.InvalidMarshallableException;
import net.openhft.chronicle.core.threads.ThreadLocalHelper;
import net.openhft.chronicle.core.util.ClassNotFoundRuntimeException;
import net.openhft.chronicle.core.util.UnresolvedType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

Expand All @@ -36,6 +37,7 @@
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.Map;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Supplier;

Expand Down Expand Up @@ -113,6 +115,7 @@ public boolean useTypes() {
return this;
}


@NotNull
@Override
protected JSONValueOut createValueOut() {
Expand Down Expand Up @@ -467,6 +470,7 @@ protected void escape0(@NotNull CharSequence s, @NotNull Quotes quotes) {
}
}
}

@Override
public ValueOut writeEvent(Class expectedType, Object eventKey) throws InvalidMarshallableException {
return super.writeEvent(String.class, "" + eventKey);
Expand Down Expand Up @@ -570,6 +574,17 @@ public void close() {

class JSONValueOut extends YamlValueOut {

@NotNull
@Override
public TextWire typeLiteral(@NotNull BiConsumer<Class, Bytes<?>> typeTranslator, Class type) {
prependSeparator();
append("{\"@type\":\"");
typeTranslator.accept(type, bytes);
append("\"}");
elementSeparator();
return wireOut();
}

@Override
protected void trimWhiteSpace() {
if (bytes.endsWith('\n') || bytes.endsWith(' '))
Expand All @@ -590,7 +605,12 @@ public String nullOut() {
@NotNull
@Override
public JSONWire typeLiteral(@Nullable CharSequence type) {
return (JSONWire) text(type);

startBlock('{');
bytes.append("\"@type\":\"" + type + "\"");
endBlock('}');

return (JSONWire) wireOut();
}

@NotNull
Expand Down Expand Up @@ -725,6 +745,68 @@ public JSONWire rawText(CharSequence value) {
}

class JSONValueIn extends TextValueIn {


@Nullable
private Type consumeTypeLiteral(BiFunction<CharSequence, ClassNotFoundException, Type> unresolvedHandler) {
long start = bytes.readPosition();
consumePadding();
StringBuilder sb = Wires.acquireStringBuilderScoped().get();

int code = readCode();
if (code != '{') {
bytes.readPosition(start);
return null;
}

consumePadding();

sb.setLength(0);
text(sb);

if (!"@type".contentEquals(sb)) {
bytes.readPosition(start);
return null;
}

consumePadding();

if (readCode() != ':') {
bytes.readPosition(start);
return null;
}

consumePadding();

sb.setLength(0);
text(sb);

String clazz = sb.toString().trim();
if (clazz.isEmpty()) {
bytes.readPosition(start);
return null;
}

consumePadding();
if (bytes.readRemaining() == 0 || bytes.readChar() != '}') {
bytes.readPosition(start);
return null;
}
consumePadding();

if (bytes.readRemaining() > 0 || peekCode() == ',') {
bytes.readSkip(1);
}
try {
return classLookup.forName(clazz);
} catch (ClassNotFoundRuntimeException e1) {
if (unresolvedHandler != null)
unresolvedHandler.apply(clazz, e1.getCause());
return UnresolvedType.of(clazz);
}
}


/**
* @return true if !!null "", if {@code true} reads the !!null "" up to the next STOP, if
* {@code false} no data is read ( data is only peaked if {@code false} )
Expand Down Expand Up @@ -784,14 +866,7 @@ public Object typePrefixOrObject(Class tClass) {

@Override
public Type typeLiteral(BiFunction<CharSequence, ClassNotFoundException, Type> unresolvedHandler) {
consumePadding();
final StringBuilder stringBuilder = acquireStringBuilder();
text(stringBuilder);
try {
return classLookup().forName(stringBuilder);
} catch (ClassNotFoundRuntimeException e) {
return unresolvedHandler.apply(stringBuilder, e.getCause());
}
return consumeTypeLiteral(unresolvedHandler);
}

@Override
Expand All @@ -818,6 +893,11 @@ private Object parseType() throws InvalidMarshallableException {
}

private <E> E parseType(@Nullable E using, @Nullable Class clazz, boolean bestEffort) throws InvalidMarshallableException {

Type aClass = consumeTypeLiteral(null);
if (aClass != null)
return (E) aClass;

if (!hasTypeDefinition()) {
return super.object(using, clazz, bestEffort);
} else {
Expand Down
29 changes: 28 additions & 1 deletion src/test/java/net/openhft/chronicle/wire/JSONWireTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import net.openhft.chronicle.core.io.IORuntimeException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.junit.Assert;
import org.junit.Test;

import java.lang.annotation.RetentionPolicy;
Expand Down Expand Up @@ -519,4 +520,30 @@ private static void readList(SimpleTwoLists record, List<String> data, ValueIn r
}
}
}
}

@Test
public void typeLiteral1() {
String expected = "{\"@net.openhft.chronicle.wire.JSONWireTest$DtoWithClassReference\":{\"implClass\":{\"@type\":\"net.openhft.chronicle.wire.JSONWireTest\"},\"bool\":false}}";
Object o = WireType.JSON_ONLY.fromString(expected);
String json = WireType.JSON_ONLY.asString(o);
Assert.assertEquals(expected, json);
}

@Test
public void typeLiteralTest2() {
DtoWithClassReference dtoWithClassReference = new DtoWithClassReference();
dtoWithClassReference.implClass = this.getClass();
String json = WireType.JSON_ONLY.asString(dtoWithClassReference);
assertEquals("{\"@net.openhft.chronicle.wire.JSONWireTest$DtoWithClassReference\"" +
":{\"implClass\":{\"@type\":\"net.openhft.chronicle.wire.JSONWireTest\"},\"bool\":false}}",
json);
assertEquals(dtoWithClassReference, WireType.JSON_ONLY.fromString(json));
}

private static class DtoWithClassReference extends SelfDescribingMarshallable {
private Class<?> implClass;
private boolean bool;
}


}

0 comments on commit 3a27cf7

Please sign in to comment.