Allow custom/external resources to be "not found" (#1471)

This allows custom/external resources to produce `null` values for
nullable reads (`read?`)

Ref: https://github.com/apple/pkl-go/issues/157
This commit is contained in:
Jen Basch
2026-03-24 12:43:44 -07:00
parent 3bdadb0bcd
commit b1fa8bea32
2 changed files with 7 additions and 10 deletions

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved. * Copyright © 2024-2026 Apple Inc. and the Pkl project authors. All rights reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -220,7 +220,6 @@ final class ExternalReaderProcessImpl implements ExternalReaderProcess {
.send( .send(
request, request,
(response) -> { (response) -> {
log(response.toString());
if (response instanceof InitializeResourceReaderResponse resp) { if (response instanceof InitializeResourceReaderResponse resp) {
var spec = var spec =
resp.spec() == null resp.spec() == null

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved. * Copyright © 2024-2026 Apple Inc. and the Pkl project authors. All rights reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -33,6 +33,7 @@ import org.pkl.core.messaging.Messages.*;
import org.pkl.core.messaging.ProtocolException; import org.pkl.core.messaging.ProtocolException;
import org.pkl.core.module.PathElement; import org.pkl.core.module.PathElement;
import org.pkl.core.resource.Resource; import org.pkl.core.resource.Resource;
import org.pkl.core.util.Nullable;
final class ExternalResourceResolverImpl implements ExternalResourceResolver { final class ExternalResourceResolverImpl implements ExternalResourceResolver {
private final MessageTransport transport; private final MessageTransport transport;
@@ -48,15 +49,14 @@ final class ExternalResourceResolverImpl implements ExternalResourceResolver {
public Optional<Object> read(URI uri) throws IOException { public Optional<Object> read(URI uri) throws IOException {
var result = doRead(uri); var result = doRead(uri);
return Optional.of(new Resource(uri, result)); return result == null ? Optional.empty() : Optional.of(new Resource(uri, result));
} }
public boolean hasElement(SecurityManager securityManager, URI elementUri) public boolean hasElement(SecurityManager securityManager, URI elementUri)
throws SecurityManagerException { throws SecurityManagerException {
securityManager.checkResolveResource(elementUri); securityManager.checkResolveResource(elementUri);
try { try {
doRead(elementUri); return doRead(elementUri) != null;
return true;
} catch (IOException e) { } catch (IOException e) {
return false; return false;
} }
@@ -98,7 +98,7 @@ final class ExternalResourceResolverImpl implements ExternalResourceResolver {
})); }));
} }
public byte[] doRead(URI baseUri) throws IOException { public byte @Nullable [] doRead(URI baseUri) throws IOException {
return MessageTransports.resolveFuture( return MessageTransports.resolveFuture(
readResponses.computeIfAbsent( readResponses.computeIfAbsent(
baseUri, baseUri,
@@ -113,10 +113,8 @@ final class ExternalResourceResolverImpl implements ExternalResourceResolver {
if (response instanceof ReadResourceResponse resp) { if (response instanceof ReadResourceResponse resp) {
if (resp.error() != null) { if (resp.error() != null) {
future.completeExceptionally(new IOException(resp.error())); future.completeExceptionally(new IOException(resp.error()));
} else if (resp.contents() != null) {
future.complete(resp.contents());
} else { } else {
future.complete(new byte[0]); future.complete(resp.contents());
} }
} else { } else {
future.completeExceptionally(new ProtocolException("unexpected response")); future.completeExceptionally(new ProtocolException("unexpected response"));