From acfc212291333b85676ca94f04c8c2d44d3c68f6 Mon Sep 17 00:00:00 2001 From: Markus KARG Date: Sat, 8 Jun 2024 15:29:58 +0000 Subject: [PATCH] PathProvider supports Path entities, in preparation for future default support in JAX-RS 4.x / Jersey 4.x. Signed-off-by: Markus KARG --- .../jersey/message/internal/PathProvider.java | 87 +++++++++++++++++++ .../jersey-common/reflect-config.json | 6 ++ .../tests/e2e/entity/EntityTypesTest.java | 21 ++++- 3 files changed, 111 insertions(+), 3 deletions(-) create mode 100644 core-common/src/main/java/org/glassfish/jersey/message/internal/PathProvider.java diff --git a/core-common/src/main/java/org/glassfish/jersey/message/internal/PathProvider.java b/core-common/src/main/java/org/glassfish/jersey/message/internal/PathProvider.java new file mode 100644 index 0000000000..461a4f85a2 --- /dev/null +++ b/core-common/src/main/java/org/glassfish/jersey/message/internal/PathProvider.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2024 Markus KARG and others. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package org.glassfish.jersey.message.internal; + +import static jakarta.ws.rs.core.MediaType.APPLICATION_OCTET_STREAM; +import static jakarta.ws.rs.core.MediaType.WILDCARD; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.lang.annotation.Annotation; +import java.lang.reflect.Type; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; + +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.MultivaluedMap; + +import jakarta.inject.Singleton; + +/** + * Provider for marshalling/un-marshalling of {@code application/octet-stream} + * entity type to/from a {@link Path} instance. + * + * @author Markus KARG + */ +@Produces({APPLICATION_OCTET_STREAM, WILDCARD}) +@Consumes({APPLICATION_OCTET_STREAM, WILDCARD}) +@Singleton +public final class PathProvider extends AbstractMessageReaderWriterProvider { + + @Override + public final boolean isReadable(final Class type, + final Type genericType, + final Annotation[] annotations, + final MediaType mediaType) { + return Path.class == type; + } + + @Override + public final Path readFrom(final Class type, + final Type genericType, + final Annotation[] annotations, + final MediaType mediaType, + final MultivaluedMap httpHeaders, + final InputStream entityStream) throws IOException { + final var path = Utils.createTempFile().toPath(); + Files.copy(entityStream, path, StandardCopyOption.REPLACE_EXISTING); + return path; + } + + @Override + public final boolean isWriteable(final Class type, + final Type genericType, + final Annotation[] annotations, + final MediaType mediaType) { + return Path.class.isAssignableFrom(type); + } + + @Override + public final void writeTo(final Path t, + final Class type, + final Type genericType, + final Annotation[] annotations, + final MediaType mediaType, + final MultivaluedMap httpHeaders, + final OutputStream entityStream) throws IOException { + Files.copy(t, entityStream); + } +} diff --git a/core-common/src/main/resources/META-INF/native-image/org.glassfish.jersey.core/jersey-common/reflect-config.json b/core-common/src/main/resources/META-INF/native-image/org.glassfish.jersey.core/jersey-common/reflect-config.json index ef2ae4d4b9..184402f495 100644 --- a/core-common/src/main/resources/META-INF/native-image/org.glassfish.jersey.core/jersey-common/reflect-config.json +++ b/core-common/src/main/resources/META-INF/native-image/org.glassfish.jersey.core/jersey-common/reflect-config.json @@ -57,6 +57,12 @@ "allDeclaredMethods":true, "allDeclaredConstructors":true }, + { + "name":"org.glassfish.jersey.message.internal.PathProvider", + "allDeclaredFields":true, + "allDeclaredMethods":true, + "allDeclaredConstructors":true + }, { "name":"org.glassfish.jersey.message.internal.FormMultivaluedMapProvider", "allDeclaredFields":true, diff --git a/tests/e2e-entity/src/test/java/org/glassfish/jersey/tests/e2e/entity/EntityTypesTest.java b/tests/e2e-entity/src/test/java/org/glassfish/jersey/tests/e2e/entity/EntityTypesTest.java index 77a74a6e9e..2a8f1990f4 100644 --- a/tests/e2e-entity/src/test/java/org/glassfish/jersey/tests/e2e/entity/EntityTypesTest.java +++ b/tests/e2e-entity/src/test/java/org/glassfish/jersey/tests/e2e/entity/EntityTypesTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2024 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0, which is available at @@ -72,6 +72,7 @@ import org.glassfish.jersey.internal.util.collection.MultivaluedStringMap; import org.glassfish.jersey.jettison.JettisonFeature; import org.glassfish.jersey.message.internal.FileProvider; +import org.glassfish.jersey.message.internal.PathProvider; import org.glassfish.jersey.server.ResourceConfig; import org.codehaus.jettison.json.JSONArray; @@ -325,13 +326,13 @@ public JaxbBean post(final JaxbBeanType t) { @Override protected Application configure() { - return ((ResourceConfig) super.configure()).register(new JettisonFeature()); + return ((ResourceConfig) super.configure()).register(new JettisonFeature()).register(new PathProvider()); } @Override protected void configureClient(final ClientConfig config) { super.configureClient(config); - config.register(new JettisonFeature()); + config.register(new JettisonFeature()).register(new PathProvider()); } @Test @@ -431,6 +432,20 @@ public void testFileRepresentation() throws IOException { _test(in, FileResource.class); } + @Path("PathResource") + public static class PathResource extends AResource { + } + + @Test + @Execution(ExecutionMode.CONCURRENT) + public void testPathRepresentation() throws IOException { + final var pp = new PathProvider(); + final var in = pp.readFrom(java.nio.file.Path.class, java.nio.file.Path.class, null, null, null, + new ByteArrayInputStream("CONTENT".getBytes())); + + _test(in, PathResource.class); + } + @Produces("application/x-www-form-urlencoded") @Consumes("application/x-www-form-urlencoded") @Path("FormResource")