Skip to content

Commit

Permalink
No InvalidTypeException from enclosingReference.
Browse files Browse the repository at this point in the history
Seemed like a good idea at the time, but it's counterproductive in practice.

Callers of enclosingReference should catch IllegalArgumentException if
they cannot convince themselves that the arguments are valid (but they
usually can).
  • Loading branch information
prdoyle committed Nov 16, 2024
1 parent fb689c8 commit 83bb473
Show file tree
Hide file tree
Showing 7 changed files with 28 additions and 58 deletions.
8 changes: 4 additions & 4 deletions bosk-core/src/main/java/works/bosk/Bosk.java
Original file line number Diff line number Diff line change
Expand Up @@ -1037,23 +1037,23 @@ public final <TT> Reference<Reference<TT>> thenReference(Class<TT> targetClass,

@SuppressWarnings("unchecked")
@Override
public final <TT> Reference<TT> enclosingReference(Class<TT> targetClass) throws InvalidTypeException {
public final <TT> Reference<TT> enclosingReference(Class<TT> targetClass) {
if (path.isEmpty()) {
throw new InvalidTypeException("Root reference has no enclosing references");
throw new IllegalArgumentException("Root reference has no enclosing references");
}
for (Path p = this.path.truncatedBy(1); !p.isEmpty(); p = p.truncatedBy(1)) try {
Type targetType = pathCompiler.targetTypeOf(p);
if (targetClass.isAssignableFrom(rawClass(targetType))) {
return rootReference().then(targetClass, p);
}
} catch (InvalidTypeException e) {
throw new InvalidTypeException("Error looking up enclosing " + targetClass.getSimpleName() + " from " + path);
throw new IllegalArgumentException("Error looking up enclosing " + targetClass.getSimpleName() + " from " + path);
}
// Might be the root
if (targetClass.isAssignableFrom(rootRef.targetClass())) {
return (Reference<TT>) rootReference();
} else {
throw new InvalidTypeException("No enclosing " + targetClass.getSimpleName() + " from " + path);
throw new IllegalArgumentException("No enclosing " + targetClass.getSimpleName() + " from " + path);
}
}

Expand Down
11 changes: 9 additions & 2 deletions bosk-core/src/main/java/works/bosk/Reference.java
Original file line number Diff line number Diff line change
Expand Up @@ -168,15 +168,22 @@ default BindingEnvironment parametersFrom(Path definitePath) {
<TT> Reference<TT> truncatedTo(Class<TT> targetClass, int remainingSegments) throws InvalidTypeException;

/**
* Returns a {@link Reference} with the {@link Path#lastSegment() last segment} removed.
*
* <p>
* <em>Design note</em>: we'd usually throw {@link InvalidTypeException} if the caller passes something invalid in here.
* However, experience has shown that almost every single time this is called, the user knows the call will always succeed,
* and just catches the {@link InvalidTypeException} and wraps it in an {@link AssertionError}.
* @param targetClass Type constraint on the reference; the returned
* reference will satisfy <code>targetClass.{@link Class#isAssignableFrom isAssignableFrom}(result.{@link
* #targetClass()})</code>.
* @return a {@link Reference} whose {@link #path()} is a proper prefix of
* this.{@link #path()}, and whose {@link #targetClass()} conforms to
* <code>targetClass</code>.
* @throws InvalidTypeException if no suitable enclosing reference exists.
* @throws IllegalArgumentException if the enclosing reference does not point to the specified {@code targetClass},
* or if this reference is the root reference and therefore has no last segment to remove.
*/
<TT> Reference<TT> enclosingReference(Class<TT> targetClass) throws InvalidTypeException;
<TT> Reference<TT> enclosingReference(Class<TT> targetClass);

/**
* @return <code>this.path().{@link Path#isPrefixOf isPrefixOf}(other.path())</code>
Expand Down
15 changes: 3 additions & 12 deletions bosk-core/src/main/java/works/bosk/SerializationPlugin.java
Original file line number Diff line number Diff line change
Expand Up @@ -288,23 +288,14 @@ public <R extends StateTreeNode> void initializeEnclosingPolyfills(Reference<?>
datatypes, a reverse postorder walk over the ParameterInfo objects should converge in a single pass.
*/
if (!target.path().isEmpty()) {
try {
initializePolyfills(target.enclosingReference(Object.class), driver);
} catch (InvalidTypeException e) {
throw new AssertionError("Every non-root reference has an enclosing reference: " + target);
}
initializePolyfills(target.enclosingReference(Object.class), driver);
}
}

private <R extends StateTreeNode, T> void initializePolyfills(Reference<T> ref, BoskDriver driver) {
initializeEnclosingPolyfills(ref, driver);
if (!ref.path().isEmpty()) {
Class<?> enclosing;
try {
enclosing = ref.enclosingReference(Object.class).targetClass();
} catch (InvalidTypeException e) {
throw new AssertionError("Every non-root reference must have an enclosing reference: " + ref);
}
Class<?> enclosing = ref.enclosingReference(Object.class).targetClass();
if (StateTreeNode.class.isAssignableFrom(enclosing)) {
Object result = infoFor(enclosing).polyfills().get(ref.path().lastSegment());
if (result != null) {
Expand All @@ -323,7 +314,7 @@ private Reference<?> findImplicitReferenceIfAny(Class<?> nodeClass, Parameter pa
Reference<Object> selfRef = selfReference(Object.class, boskInfo);
try {
return selfRef.enclosingReference(targetClass);
} catch (InvalidTypeException e) {
} catch (IllegalArgumentException e) {
// TODO: Validation needs to check that every location
// where this type appears in the document tree is
// contained in a document of the target class.
Expand Down
15 changes: 1 addition & 14 deletions bosk-mongo/src/main/java/works/bosk/drivers/mongo/Formatter.java
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,7 @@ static <T> List<String> containerSegments(Reference<T> elementRef, int elementRe
*/
private static <T> void buildDottedFieldNameOf(Reference<T> ref, int startLength, int refLength, ArrayList<String> segments) {
if (ref.path().length() > startLength) {
Reference<?> enclosingReference = enclosingReference(ref);
Reference<?> enclosingReference = ref.enclosingReference(Object.class);
buildDottedFieldNameOf(enclosingReference, startLength, refLength, segments);
if (ref.path().length() <= refLength) {
if (Listing.class.isAssignableFrom(enclosingReference.targetClass())) {
Expand Down Expand Up @@ -409,19 +409,6 @@ private static void skipField(Reference<?> ref, Iterator<String> iter, String ex
}
}

/**
* If the reference is not a root reference, it always has an enclosing reference
* conforming to Object, so this can't throw. Eat the InvalidTypeException.
*/
static <T> Reference<?> enclosingReference(Reference<T> ref) {
assert !ref.path().isEmpty();
try {
return ref.enclosingReference(Object.class);
} catch (InvalidTypeException e) {
throw new AssertionError(format("Reference must have an enclosing Object: '%s'", ref), e);
}
}

private static final UnaryOperator<String> DECODER;
private static final UnaryOperator<String> ENCODER;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -556,15 +556,11 @@ private <T> void doReplacement(Reference<T> target, T newValue) {
LOGGER.debug("| Filter: {}", filter);
collection.updateOne(filter, update, new UpdateOptions().upsert(true));

try {
// Move up to the parent document to set the "true" stub
mainRef = mainRef(mainRef.enclosingReference(Object.class));
filter = documentFilter(mainRef);
value = TRUE;
LOGGER.debug("| Move up to enclosing main reference {}", mainRef);
} catch (InvalidTypeException e) {
throw new AssertionError("Every non-root reference has an enclosing reference");
}
// Move up to the parent document to set the "true" stub
mainRef = mainRef(mainRef.enclosingReference(Object.class));
filter = documentFilter(mainRef);
value = TRUE;
LOGGER.debug("| Move up to enclosing main reference {}", mainRef);
}

// Update part of the main doc (which must already exist)
Expand Down Expand Up @@ -594,13 +590,9 @@ private <T> void doDelete(Reference<T> target) {
}

assert !mainRef.path().isEmpty(): "Can't delete the root reference";
try {
// Move up to the parent document to delete the "true" stub
mainRef = mainRef(mainRef.enclosingReference(Object.class));
LOGGER.debug("Move up to enclosing main reference {}", mainRef);
} catch (InvalidTypeException e) {
throw new AssertionError("Every non-root reference has an enclosing reference");
}
// Move up to the parent document to delete the "true" stub
mainRef = mainRef(mainRef.enclosingReference(Object.class));
LOGGER.debug("Move up to enclosing main reference {}", mainRef);
}
if (doUpdate(deletionDoc(target, mainRef), standardPreconditions(target, mainRef, documentFilter(mainRef)))) {
if (!rootRef.equals(mainRef)) {
Expand Down Expand Up @@ -713,7 +705,7 @@ private <T> BsonDocument standardRootPreconditions(Reference<T> target) {

private <T> BsonDocument standardPreconditions(Reference<T> target, Reference<?> startingRef, BsonDocument filter) {
if (!target.path().equals(startingRef.path())) {
String enclosingObjectKey = Formatter.dottedFieldNameOf(Formatter.enclosingReference(target), startingRef);
String enclosingObjectKey = Formatter.dottedFieldNameOf(target.enclosingReference(Object.class), startingRef);
BsonDocument condition = new BsonDocument("$type", new BsonString("object"));
filter.put(enclosingObjectKey, condition);
LOGGER.debug("| Precondition: {} {}", enclosingObjectKey, condition);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@
import static org.bson.BsonBoolean.FALSE;
import static works.bosk.drivers.mongo.Formatter.REVISION_ZERO;
import static works.bosk.drivers.mongo.Formatter.dottedFieldNameOf;
import static works.bosk.drivers.mongo.Formatter.enclosingReference;
import static works.bosk.drivers.mongo.Formatter.referenceTo;
import static works.bosk.drivers.mongo.MainDriver.MANIFEST_ID;
import static works.bosk.drivers.mongo.MongoDriverSettings.ManifestMode.CREATE_IF_ABSENT;
Expand Down Expand Up @@ -328,7 +327,7 @@ private BsonDocument documentFilter() {
private <T> BsonDocument standardPreconditions(Reference<T> target) {
BsonDocument filter = documentFilter();
if (!target.path().isEmpty()) {
String enclosingObjectKey = dottedFieldNameOf(enclosingReference(target), rootRef);
String enclosingObjectKey = dottedFieldNameOf(target.enclosingReference(Object.class), rootRef);
BsonDocument condition = new BsonDocument("$type", new BsonString("object"));
filter.put(enclosingObjectKey, condition);
LOGGER.debug("| Precondition: {} {}", enclosingObjectKey, condition);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,13 +68,7 @@ protected TestEntity autoInitialize(Reference<TestEntity> ref) {
// Root always exists; nothing to do
return null;
} else {
Reference<TestEntity> outer;
try {
outer = ref.enclosingReference(TestEntity.class);
} catch (InvalidTypeException e) {
throw new AssertionError("Every entity besides the root should be inside another entity", e);
}
autoInitialize(outer);
autoInitialize(ref.enclosingReference(TestEntity.class));
TestEntity newEntity = emptyEntityAt(ref);
driver.submitInitialization(ref, newEntity);
return newEntity;
Expand Down

0 comments on commit 83bb473

Please sign in to comment.