1414import java .util .function .Function ;
1515
1616import edu .umd .cs .findbugs .annotations .NonNull ;
17- import io .jooby .Context ;
18- import io .jooby .MediaType ;
19- import io .jooby .Route ;
20- import io .jooby .StatusCode ;
17+ import edu .umd .cs .findbugs .annotations .Nullable ;
18+ import io .jooby .*;
2119
2220/**
2321 * Handler for static resources represented by the {@link Asset} contract.
2826 * @since 2.0.0
2927 */
3028public class AssetHandler implements Route .Handler {
29+ private static final SneakyThrows .Consumer <Context > NOT_FOUND =
30+ ctx -> ctx .send (StatusCode .NOT_FOUND );
3131 private static final int ONE_SEC = 1000 ;
3232
3333 private final AssetSource [] sources ;
@@ -41,6 +41,7 @@ public class AssetHandler implements Route.Handler {
4141 private Function <String , CacheControl > cacheControl = path -> defaults ;
4242
4343 private Function <Asset , MediaType > mediaTypeResolver = Asset ::getContentType ;
44+ private SneakyThrows .Consumer <Context > notFound = NOT_FOUND ;
4445
4546 /**
4647 * Creates a new asset handler that fallback to the given fallback asset when the asset is not
@@ -82,7 +83,7 @@ public Object apply(@NonNull Context ctx) throws Exception {
8283 }
8384 // Still null?
8485 if (asset == null ) {
85- ctx . send ( StatusCode . NOT_FOUND );
86+ notFound . accept ( ctx );
8687 return ctx ;
8788 } else {
8889 resolvedPath = fallback ;
@@ -230,7 +231,19 @@ public AssetHandler cacheControl(@NonNull Function<String, CacheControl> cacheCo
230231 return this ;
231232 }
232233
233- private Asset resolve (String filepath ) {
234+ /**
235+ * Sets a custom handler for <code>404</code> asset/resource. By default, generates a <code>404
236+ * </code> status code response.
237+ *
238+ * @param handler Handler.
239+ * @return This handler.
240+ */
241+ public AssetHandler notFound (@ NonNull SneakyThrows .Consumer <Context > handler ) {
242+ this .notFound = handler ;
243+ return this ;
244+ }
245+
246+ private @ Nullable Asset resolve (String filepath ) {
234247 for (AssetSource source : sources ) {
235248 Asset asset = source .resolve (filepath );
236249 if (asset != null ) {
@@ -243,7 +256,7 @@ private Asset resolve(String filepath) {
243256 @ Override
244257 public void setRoute (Route route ) {
245258 List <String > keys = route .getPathKeys ();
246- this .filekey = keys .size () == 0 ? route .getPattern ().substring (1 ) : keys .get (0 );
259+ this .filekey = keys .isEmpty () ? route .getPattern ().substring (1 ) : keys .get (0 );
247260 // NOTE: It send an inputstream we don't need a renderer
248261 route .setReturnType (Context .class );
249262 }
0 commit comments