Skip to content

Commit

Permalink
try fixing by making the writer aware of the inner type of the Reference
Browse files Browse the repository at this point in the history
  • Loading branch information
radeusgd committed May 24, 2024
1 parent 5eaee6a commit c4d0e72
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@
import javax.lang.model.element.PackageElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.SimpleAnnotationValueVisitor9;
import javax.lang.model.util.SimpleTypeVisitor14;
import javax.tools.Diagnostic.Kind;
import org.openide.util.lookup.ServiceProvider;

Expand Down Expand Up @@ -245,7 +247,21 @@ public int compare(Object a, Object b) {
var type = tu.erasure(v.asType());
var elem = (TypeElement) tu.asElement(type);
var name = findFqn(elem);
if (canInline && shouldInline(elem)) {
if (name.equals("org.enso.persist.Persistance.Reference")) {
if (!canInline) {
throw new IllegalArgumentException(
"Reference fields can currently only be stored as inlined objects.");
}

TypeMirror innerType = extractReferenceInnerType(v.asType());
var innerElem = (TypeElement) tu.asElement(tu.erasure(innerType));
var innerName = findFqn(innerElem);
w.append(" out.writeInlineReference(")
.append(innerName)
.append(".class, obj.")
.append(v.getSimpleName())
.append("());\n");
} else if (canInline && shouldInline(elem)) {
w.append(" out.writeInline(")
.append(name)
.append(".class, obj.")
Expand Down Expand Up @@ -274,6 +290,30 @@ public int compare(Object a, Object b) {
return true;
}

private TypeMirror extractReferenceInnerType(TypeMirror reference) {
return reference.accept(
new SimpleTypeVisitor14<TypeMirror, Void>() {
@Override
protected TypeMirror defaultAction(TypeMirror t, Void o) {
throw new IllegalStateException(
"Unexpected type: " + t + ", Persistance.Reference was expected.");
}

@Override
public TypeMirror visitDeclared(DeclaredType t, Void unused) {
var typeArgs = t.getTypeArguments();
if (typeArgs.size() != 1) {
throw new IllegalStateException(
"Unexpected number of type arguments for Persistance.Reference: "
+ typeArgs.size());
}

return typeArgs.get(0);
}
},
null);
}

private int countSeq(List<? extends VariableElement> parameters) {
var tu = processingEnv.getTypeUtils();
var cnt = 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,8 @@ final int versionStamp() {
return map.versionStamp;
}

private int registerReference(Persistance.Reference<?> ref) {
var obj = ref.get(Object.class);
private <T> int registerReference(Class<T> clazz, Persistance.Reference<T> ref) {
var obj = ref.get(clazz);
if (obj == null) {
// A null reference is represented by id -1
return -1;
Expand Down Expand Up @@ -188,16 +188,21 @@ private static final class ReferenceOutput extends DataOutputStream
@Override
public <T> void writeInline(Class<T> clazz, T t) throws IOException {
if (Persistance.Reference.class == clazz) {
Persistance.Reference<?> ref = (Persistance.Reference<?>) t;
var id = this.generator.registerReference(ref);
writeInt(id);
return;
throw new IllegalStateException(
"writeInlineReference should have been used for Persistance.Reference");
}
var obj = generator.writeReplace.apply(t);
var p = generator.map.forType(clazz);
p.writeInline(obj, this);
}

@Override
public <T> void writeInlineReference(Class<T> clazz, Persistance.Reference<T> ref)
throws IOException {
var id = this.generator.registerReference(clazz, ref);
writeInt(id);
}

@Override
public void writeObject(Object obj) throws IOException {
this.generator.writeIndirect(obj, this);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,9 @@ public static interface Output extends DataOutput {
*/
public abstract <T> void writeInline(Class<T> clazz, T obj) throws IOException;

public abstract <T> void writeInlineReference(Class<T> clazz, Reference<T> ref)
throws IOException;

/**
* Writes an object as a "reference". Objects written by this method are shared - each {@code
* obj} is stored only once and referenced from all the locations it is used.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;

import java.io.IOException;
import java.util.UUID;
Expand Down Expand Up @@ -249,7 +250,6 @@ public void testLoopsBetweenDifferentTypes() throws Exception {
}
}


@Test
public void testReferenceLoopsSavedTwiceInPersistance() throws Exception {
var obj3 = new LongerLoop3("a", null);
Expand All @@ -258,10 +258,21 @@ public void testReferenceLoopsSavedTwiceInPersistance() throws Exception {
obj3.y = Persistance.Reference.of(obj1);

var loaded1 = serde(LongerLoop1.class, obj1, -1);
// Now we serialize the deserialized object again - this is to test that references read from file can be serialized back to a file.
assertTrue(
"The loaded reference should be a PerBufferReference, not PerMemoryReference",
loaded1.y() instanceof PerBufferReference<?>);

// Now we serialize the deserialized object again - this is to test that references read from
// file can be serialized back to a file.
var loadedAgain = serde(LongerLoop1.class, loaded1, -1);
System.out.println(loadedAgain.y());
var r2 = loadedAgain.y().get(LongerLoop2.class).y().get(LongerLoop3.class).y().get(LongerLoop1.class);
var r2 =
loadedAgain
.y()
.get(LongerLoop2.class)
.y()
.get(LongerLoop3.class)
.y()
.get(LongerLoop1.class);
assertSame("The recreated structure contains the loop", loadedAgain, r2);
}

Expand Down

0 comments on commit c4d0e72

Please sign in to comment.