From f0e0106dc24663294fdc9d787981c118c2236d99 Mon Sep 17 00:00:00 2001 From: Maxim Nesen <maxim.nesen@oracle.com> Date: Fri, 26 Feb 2021 13:50:07 +0100 Subject: [PATCH 1/9] processing order for Jackson/Jaxb annotations Signed-off-by: Maxim Nesen <maxim.nesen@oracle.com> --- .../DefaultJacksonJaxbJsonProvider.java | 25 ++++++++++++------- .../jackson/internal/model/ServiceTest.java | 4 ++- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/DefaultJacksonJaxbJsonProvider.java b/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/DefaultJacksonJaxbJsonProvider.java index 8b4ce1ce9f..8219cb1111 100644 --- a/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/DefaultJacksonJaxbJsonProvider.java +++ b/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/DefaultJacksonJaxbJsonProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2021 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 @@ -17,10 +17,11 @@ package org.glassfish.jersey.jackson.internal; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.Module; import org.glassfish.jersey.jackson.internal.jackson.jaxrs.cfg.Annotations; import org.glassfish.jersey.jackson.internal.jackson.jaxrs.json.JacksonJaxbJsonProvider; -import java.util.Objects; +import java.util.List; import javax.inject.Singleton; /** @@ -29,7 +30,11 @@ @Singleton public class DefaultJacksonJaxbJsonProvider extends JacksonJaxbJsonProvider { + //do not register JaxbAnnotationModule because it brakes default annotations processing + private static final String EXCLUDE_MODULE_NAME = "JaxbAnnotationModule"; + public DefaultJacksonJaxbJsonProvider() { + super(); findAndRegisterModules(); } @@ -39,14 +44,16 @@ public DefaultJacksonJaxbJsonProvider(final Annotations... annotationsToUse) { } private void findAndRegisterModules() { - final ObjectMapper defaultMapper = _mapperConfig.getDefaultMapper(); - if (Objects.nonNull(defaultMapper)) { - defaultMapper.findAndRegisterModules(); - } + final ObjectMapper defaultMapper = _mapperConfig.getDefaultMapper(); final ObjectMapper mapper = _mapperConfig.getConfiguredMapper(); - if (Objects.nonNull(mapper)) { - mapper.findAndRegisterModules(); + + final List<Module> modules = ObjectMapper.findModules(); + modules.removeIf(mod -> mod.getModuleName().contains(EXCLUDE_MODULE_NAME)); + + defaultMapper.registerModules(modules); + if (mapper != null) { + mapper.registerModules(modules); } } -} +} \ No newline at end of file diff --git a/media/json-jackson/src/test/java/org/glassfish/jersey/jackson/internal/model/ServiceTest.java b/media/json-jackson/src/test/java/org/glassfish/jersey/jackson/internal/model/ServiceTest.java index 027064b27b..f3a664cc06 100644 --- a/media/json-jackson/src/test/java/org/glassfish/jersey/jackson/internal/model/ServiceTest.java +++ b/media/json-jackson/src/test/java/org/glassfish/jersey/jackson/internal/model/ServiceTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2021 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 @@ -23,6 +23,7 @@ import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; +import javax.xml.bind.annotation.XmlElement; @Path("/entity/") public final class ServiceTest { @@ -45,6 +46,7 @@ private static final class EntityTest { this.value = value; } + @XmlElement(name = "jaxb") @JsonGetter("name") public final String getName() { return name; From 6b87643f8b974af6bd600e4d58a026c3a0f5e33d Mon Sep 17 00:00:00 2001 From: Denis Kurochkin <dkurochkin@smartling.com> Date: Wed, 31 Mar 2021 15:36:06 +0300 Subject: [PATCH 2/9] Proper handling of chunked input streams in LoggingInterceptor (#4753) Signed-off-by: Denis Kurochkin <d.k.brazz@gmail.com> --- core-common/pom.xml | 7 +- .../jersey/logging/LoggingInterceptor.java | 13 +++- .../logging/LoggingInterceptorTest.java | 78 ++++++++++++++++++- .../src/test/resources/surefire.policy | 5 +- 4 files changed, 98 insertions(+), 5 deletions(-) diff --git a/core-common/pom.xml b/core-common/pom.xml index 3288c5f45b..e36288f6c0 100644 --- a/core-common/pom.xml +++ b/core-common/pom.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2010, 2020 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2010, 2021 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 @@ -210,6 +210,11 @@ <artifactId>junit</artifactId> <scope>test</scope> </dependency> + <dependency> + <groupId>org.mockito</groupId> + <artifactId>mockito-all</artifactId> + <scope>test</scope> + </dependency> <dependency> <groupId>org.hamcrest</groupId> <artifactId>hamcrest-library</artifactId> diff --git a/core-common/src/main/java/org/glassfish/jersey/logging/LoggingInterceptor.java b/core-common/src/main/java/org/glassfish/jersey/logging/LoggingInterceptor.java index c90d8b6470..7ad26ec5d6 100644 --- a/core-common/src/main/java/org/glassfish/jersey/logging/LoggingInterceptor.java +++ b/core-common/src/main/java/org/glassfish/jersey/logging/LoggingInterceptor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2021 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 @@ -193,7 +193,16 @@ InputStream logInboundEntity(final StringBuilder b, InputStream stream, final Ch } stream.mark(maxEntitySize + 1); final byte[] entity = new byte[maxEntitySize + 1]; - final int entitySize = stream.read(entity); + + int entitySize = 0; + while (entitySize < entity.length) { + int readBytes = stream.read(entity, entitySize, entity.length - entitySize); + if (readBytes < 0) { + break; + } + entitySize += readBytes; + } + b.append(new String(entity, 0, Math.min(entitySize, maxEntitySize), charset)); if (entitySize > maxEntitySize) { b.append("...more..."); diff --git a/core-common/src/test/java/org/glassfish/jersey/logging/LoggingInterceptorTest.java b/core-common/src/test/java/org/glassfish/jersey/logging/LoggingInterceptorTest.java index e4e5e91480..55162737e4 100644 --- a/core-common/src/test/java/org/glassfish/jersey/logging/LoggingInterceptorTest.java +++ b/core-common/src/test/java/org/glassfish/jersey/logging/LoggingInterceptorTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2019 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2021 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 @@ -16,14 +16,27 @@ package org.glassfish.jersey.logging; +import org.mockito.stubbing.Answer; + import javax.ws.rs.core.MediaType; +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.Random; import org.junit.Test; import static org.glassfish.jersey.logging.LoggingFeature.Verbosity.HEADERS_ONLY; import static org.glassfish.jersey.logging.LoggingFeature.Verbosity.PAYLOAD_ANY; import static org.glassfish.jersey.logging.LoggingFeature.Verbosity.PAYLOAD_TEXT; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import static javax.ws.rs.core.MediaType.APPLICATION_OCTET_STREAM_TYPE; import static javax.ws.rs.core.MediaType.TEXT_HTML_TYPE; @@ -106,4 +119,67 @@ public void testVerbosityHeadersPrintBinaryEntity() { assertFalse(LoggingInterceptor.printEntity(HEADERS_ONLY, APPLICATION_OCTET_STREAM_TYPE)); } + // + // logInboundEntity + // + + @Test + public void testLogInboundEntityMockedStream() throws Exception { + int maxEntitySize = 20; + LoggingInterceptor loggingInterceptor = new LoggingInterceptor(null, null, null, maxEntitySize) {}; + + StringBuilder buffer = new StringBuilder(); + InputStream stream = mock(InputStream.class); + when(stream.markSupported()).thenReturn(true); + + when(stream.read(any(), eq(0), eq(maxEntitySize + 1))) + .thenAnswer(chunk(4, 'a')); + when(stream.read(any(), eq(4), eq(maxEntitySize + 1 - 4))) + .thenAnswer(chunk(3, 'b')); + when(stream.read(any(), eq(7), eq(maxEntitySize + 1 - 7))) + .thenAnswer(chunk(5, 'c')); + when(stream.read(any(), eq(12), eq(maxEntitySize + 1 - 12))) + .thenReturn(-1); + + loggingInterceptor.logInboundEntity(buffer, stream, StandardCharsets.UTF_8); + + assertEquals("aaaabbbccccc\n", buffer.toString()); + verify(stream).mark(maxEntitySize + 1); + verify(stream).reset(); + } + + private Answer<?> chunk(int size, char filler) { + return invocation -> { + byte[] buf = invocation.getArgumentAt(0, byte[].class); + int offset = invocation.getArgumentAt(1, Integer.class); + Arrays.fill(buf, offset, offset + size, (byte) filler); + return size; + }; + } + + @Test + public void testLogInboundEntityRealStream() throws Exception { + int maxEntitySize = 2000; + String inputString = getRandomString(maxEntitySize * 2); + + LoggingInterceptor loggingInterceptor = new LoggingInterceptor(null, null, null, maxEntitySize) {}; + StringBuilder buffer = new StringBuilder(); + InputStream stream = new ByteArrayInputStream(inputString.getBytes()); + + loggingInterceptor.logInboundEntity(buffer, stream, StandardCharsets.UTF_8); + + assertEquals(inputString.substring(0, maxEntitySize) + "...more...\n", buffer.toString()); + } + + private static String getRandomString(int length) { + final String characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890 _"; + StringBuilder result = new StringBuilder(); + + while (length > 0) { + Random rand = new Random(); + result.append(characters.charAt(rand.nextInt(characters.length()))); + length--; + } + return result.toString(); + } } diff --git a/core-common/src/test/resources/surefire.policy b/core-common/src/test/resources/surefire.policy index 27602ae4c0..530db3cf62 100644 --- a/core-common/src/test/resources/surefire.policy +++ b/core-common/src/test/resources/surefire.policy @@ -29,12 +29,15 @@ grant codebase "file:${settings.localRepository}/-" { grant codebase "file:${project.build.directory}/test-classes/-" { permission java.lang.reflect.ReflectPermission "suppressAccessChecks"; permission java.lang.RuntimePermission "modifyThread"; - permission java.util.PropertyPermission "*", "write"; + permission java.util.PropertyPermission "*", "read,write"; permission java.io.FilePermission "${java.io.tmpdir}/-", "read,write,delete"; permission java.lang.RuntimePermission "getClassLoader"; permission java.lang.RuntimePermission "accessClassInPackage.sun.misc"; permission java.lang.RuntimePermission "accessClassInPackage.sun.misc.*"; permission java.lang.reflect.ReflectPermission "suppressAccessChecks"; + permission java.lang.RuntimePermission "accessDeclaredMembers"; + permission java.lang.RuntimePermission "accessClassInPackage.sun.reflect"; + permission java.lang.RuntimePermission "reflectionFactoryAccess"; }; grant codebase "file:${project.build.directory}/classes/-" { From 0d58cf900aab0a34a424f5b88a8874df45601082 Mon Sep 17 00:00:00 2001 From: Maxim Nesen <24524084+senivam@users.noreply.github.com> Date: Mon, 12 Apr 2021 10:21:06 +0200 Subject: [PATCH 3/9] Logging delimiter parametrized (#4745) Signed-off-by: Maxim Nesen <maxim.nesen@oracle.com> --- .../jersey/logging/ClientLoggingFilter.java | 18 +- .../jersey/logging/LoggingFeature.java | 166 ++++++++++++++---- .../LoggingFeatureAutoDiscoverable.java | 14 +- .../jersey/logging/LoggingInterceptor.java | 39 ++-- .../jersey/logging/ServerLoggingFilter.java | 18 +- .../logging/LoggingInterceptorTest.java | 4 +- docs/src/main/docbook/appendix-properties.xml | 33 ++++ docs/src/main/docbook/jersey.ent | 10 +- .../tests/e2e/common/LoggingFeatureTest.java | 41 ++++- 9 files changed, 264 insertions(+), 79 deletions(-) diff --git a/core-common/src/main/java/org/glassfish/jersey/logging/ClientLoggingFilter.java b/core-common/src/main/java/org/glassfish/jersey/logging/ClientLoggingFilter.java index 1cd5cdb86e..07c3dbeca6 100644 --- a/core-common/src/main/java/org/glassfish/jersey/logging/ClientLoggingFilter.java +++ b/core-common/src/main/java/org/glassfish/jersey/logging/ClientLoggingFilter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2019 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2021 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 @@ -53,18 +53,20 @@ final class ClientLoggingFilter extends LoggingInterceptor implements ClientRequestFilter, ClientResponseFilter { /** - * Create a logging filter with custom logger and custom settings of entity + * Create a logging filter using builder instance with custom logger and custom settings of entity * logging. * - * @param logger the logger to log messages to. - * @param level level at which the messages will be logged. - * @param verbosity verbosity of the logged messages. See {@link Verbosity}. - * @param maxEntitySize maximum number of entity bytes to be logged (and buffered) - if the entity is larger, + * @param builder loggingFeatureBuilder which contains values for: + * logger the logger to log messages to. + * level level at which the messages will be logged. + * verbosity verbosity of the logged messages. See {@link Verbosity}. + * maxEntitySize maximum number of entity bytes to be logged (and buffered) - if the entity is larger, * logging filter will print (and buffer in memory) only the specified number of bytes * and print "...more..." string at the end. Negative values are interpreted as zero. + * separator delimiter for particular log lines. Default is Linux new line delimiter */ - public ClientLoggingFilter(final Logger logger, final Level level, final Verbosity verbosity, final int maxEntitySize) { - super(logger, level, verbosity, maxEntitySize); + public ClientLoggingFilter(LoggingFeature.LoggingFeatureBuilder builder) { + super(builder); } @Override diff --git a/core-common/src/main/java/org/glassfish/jersey/logging/LoggingFeature.java b/core-common/src/main/java/org/glassfish/jersey/logging/LoggingFeature.java index e4e2b01f03..e6ed421d5f 100644 --- a/core-common/src/main/java/org/glassfish/jersey/logging/LoggingFeature.java +++ b/core-common/src/main/java/org/glassfish/jersey/logging/LoggingFeature.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2019 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2021 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 @@ -40,6 +40,7 @@ * <li>{@link #LOGGING_FEATURE_LOGGER_LEVEL}</li> * <li>{@link #LOGGING_FEATURE_VERBOSITY}</li> * <li>{@link #LOGGING_FEATURE_MAX_ENTITY_SIZE}</li> + * <li>{@link #LOGGING_FEATURE_SEPARATOR}</li> * </ul> * <p> * If any of the configuration value is not set, following default values are applied: @@ -56,6 +57,7 @@ * <li>{@link #LOGGING_FEATURE_LOGGER_LEVEL_SERVER}</li> * <li>{@link #LOGGING_FEATURE_VERBOSITY_SERVER}</li> * <li>{@link #LOGGING_FEATURE_MAX_ENTITY_SIZE_SERVER}</li> + * <li>{@link #LOGGING_FEATURE_SEPARATOR_SERVER}</li> * </ul> * Client configurable properties: * <ul> @@ -63,6 +65,7 @@ * <li>{@link #LOGGING_FEATURE_LOGGER_LEVEL_CLIENT}</li> * <li>{@link #LOGGING_FEATURE_VERBOSITY_CLIENT}</li> * <li>{@link #LOGGING_FEATURE_MAX_ENTITY_SIZE_CLIENT}</li> + * <li>{@link #LOGGING_FEATURE_SEPARATOR_CLIENT}</li> * </ul> * * @author Ondrej Kosatka @@ -86,11 +89,16 @@ public class LoggingFeature implements Feature { * Default verbosity for entity logging. See {@link Verbosity}. */ public static final Verbosity DEFAULT_VERBOSITY = Verbosity.PAYLOAD_TEXT; + /** + * Default separator for entity logging. + */ + public static final String DEFAULT_SEPARATOR = "\n"; private static final String LOGGER_NAME_POSTFIX = ".logger.name"; private static final String LOGGER_LEVEL_POSTFIX = ".logger.level"; private static final String VERBOSITY_POSTFIX = ".verbosity"; private static final String MAX_ENTITY_POSTFIX = ".entity.maxSize"; + private static final String SEPARATOR_POSTFIX = ".separator"; private static final String LOGGING_FEATURE_COMMON_PREFIX = "jersey.config.logging"; /** * Common logger name property. @@ -108,6 +116,10 @@ public class LoggingFeature implements Feature { * Common property for configuring a maximum number of bytes of entity to be logged. */ public static final String LOGGING_FEATURE_MAX_ENTITY_SIZE = LOGGING_FEATURE_COMMON_PREFIX + MAX_ENTITY_POSTFIX; + /** + * Common property for configuring logging separator. + */ + public static final String LOGGING_FEATURE_SEPARATOR = LOGGING_FEATURE_COMMON_PREFIX + SEPARATOR_POSTFIX; private static final String LOGGING_FEATURE_SERVER_PREFIX = "jersey.config.server.logging"; /** @@ -126,6 +138,10 @@ public class LoggingFeature implements Feature { * Server property for configuring a maximum number of bytes of entity to be logged. */ public static final String LOGGING_FEATURE_MAX_ENTITY_SIZE_SERVER = LOGGING_FEATURE_SERVER_PREFIX + MAX_ENTITY_POSTFIX; + /** + * Server property for configuring separator. + */ + public static final String LOGGING_FEATURE_SEPARATOR_SERVER = LOGGING_FEATURE_SERVER_PREFIX + SEPARATOR_POSTFIX; private static final String LOGGING_FEATURE_CLIENT_PREFIX = "jersey.config.client.logging"; /** @@ -144,11 +160,12 @@ public class LoggingFeature implements Feature { * Client property for configuring a maximum number of bytes of entity to be logged. */ public static final String LOGGING_FEATURE_MAX_ENTITY_SIZE_CLIENT = LOGGING_FEATURE_CLIENT_PREFIX + MAX_ENTITY_POSTFIX; + /** + * Client property for logging separator. + */ + public static final String LOGGING_FEATURE_SEPARATOR_CLIENT = LOGGING_FEATURE_CLIENT_PREFIX + SEPARATOR_POSTFIX; - private final Logger filterLogger; - private final Verbosity verbosity; - private final Integer maxEntitySize; - private final Level level; + private final LoggingFeatureBuilder builder; /** * Creates the feature with default values. @@ -199,32 +216,62 @@ public LoggingFeature(Logger logger, Integer maxEntitySize) { * and print "...more..." string at the end. Negative values are interpreted as zero. */ public LoggingFeature(Logger logger, Level level, Verbosity verbosity, Integer maxEntitySize) { - this.filterLogger = logger; - this.level = level; - this.verbosity = verbosity; - this.maxEntitySize = maxEntitySize; + + this(LoggingFeature.builder() + .withLogger(logger) + .level(level) + .verbosity(verbosity) + .maxEntitySize(maxEntitySize) + .separator(DEFAULT_SEPARATOR) + ); + + } + + /** + * Constructor based on logging feature builder. All parameters are passed through a builder instance. + * + * @param builder instance of a builder with required logging feature parameters + */ + public LoggingFeature(LoggingFeatureBuilder builder) { + this.builder = builder; } @Override public boolean configure(FeatureContext context) { - boolean enabled = false; + boolean enabled = context.getConfiguration().getRuntimeType() != null; - if (context.getConfiguration().getRuntimeType() == RuntimeType.CLIENT) { - ClientLoggingFilter clientLoggingFilter = (ClientLoggingFilter) createLoggingFilter(context, RuntimeType.CLIENT); - context.register(clientLoggingFilter); - enabled = true; - } - if (context.getConfiguration().getRuntimeType() == RuntimeType.SERVER) { - ServerLoggingFilter serverClientFilter = (ServerLoggingFilter) createLoggingFilter(context, RuntimeType.SERVER); - context.register(serverClientFilter); - enabled = true; + if (enabled) { + context.register(createLoggingFilter(context, context.getConfiguration().getRuntimeType())); } + return enabled; } + /** + * builder method to create LoggingFeature with required settings + * + * @return Builder for LoggingFeature + */ + public static LoggingFeatureBuilder builder() { + return new LoggingFeatureBuilder(); + } + private LoggingInterceptor createLoggingFilter(FeatureContext context, RuntimeType runtimeType) { - Map properties = context.getConfiguration().getProperties(); - String filterLoggerName = CommonProperties.getValue( + + final LoggingFeatureBuilder loggingBuilder = + configureBuilderParameters(builder, context, runtimeType); + + return (runtimeType == RuntimeType.SERVER) + ? new ServerLoggingFilter(loggingBuilder) + : new ClientLoggingFilter(loggingBuilder); + } + + private static LoggingFeatureBuilder configureBuilderParameters(LoggingFeatureBuilder builder, + FeatureContext context, RuntimeType runtimeType) { + + final Map properties = context.getConfiguration().getProperties(); + //get values from properties (if any) + final String filterLoggerName = CommonProperties.getValue( properties, runtimeType == RuntimeType.SERVER ? LOGGING_FEATURE_LOGGER_NAME_SERVER : LOGGING_FEATURE_LOGGER_NAME_CLIENT, CommonProperties.getValue( @@ -232,14 +279,21 @@ private LoggingInterceptor createLoggingFilter(FeatureContext context, RuntimeTy LOGGING_FEATURE_LOGGER_NAME, DEFAULT_LOGGER_NAME )); - String filterLevel = CommonProperties.getValue( + final String filterLevel = CommonProperties.getValue( properties, runtimeType == RuntimeType.SERVER ? LOGGING_FEATURE_LOGGER_LEVEL_SERVER : LOGGING_FEATURE_LOGGER_LEVEL_CLIENT, CommonProperties.getValue( context.getConfiguration().getProperties(), LOGGING_FEATURE_LOGGER_LEVEL, DEFAULT_LOGGER_LEVEL)); - Verbosity filterVerbosity = CommonProperties.getValue( + final String filterSeparator = CommonProperties.getValue( + properties, + runtimeType == RuntimeType.SERVER ? LOGGING_FEATURE_SEPARATOR_SERVER : LOGGING_FEATURE_SEPARATOR_CLIENT, + CommonProperties.getValue( + context.getConfiguration().getProperties(), + LOGGING_FEATURE_SEPARATOR, + DEFAULT_SEPARATOR)); + final Verbosity filterVerbosity = CommonProperties.getValue( properties, runtimeType == RuntimeType.SERVER ? LOGGING_FEATURE_VERBOSITY_SERVER : LOGGING_FEATURE_VERBOSITY_CLIENT, CommonProperties.getValue( @@ -257,19 +311,16 @@ private LoggingInterceptor createLoggingFilter(FeatureContext context, RuntimeTy DEFAULT_MAX_ENTITY_SIZE )); - Level loggerLevel = Level.parse(filterLevel); - - if (runtimeType == RuntimeType.SERVER) { - return new ServerLoggingFilter(filterLogger != null ? filterLogger : Logger.getLogger(filterLoggerName), - level != null ? level : loggerLevel, - verbosity != null ? verbosity : filterVerbosity, - maxEntitySize != null ? maxEntitySize : filterMaxEntitySize); - } else { - return new ClientLoggingFilter(filterLogger != null ? filterLogger : Logger.getLogger(filterLoggerName), - level != null ? level : loggerLevel, - verbosity != null ? verbosity : filterVerbosity, - maxEntitySize != null ? maxEntitySize : filterMaxEntitySize); - } + final Level loggerLevel = Level.parse(filterLevel); + + //configure builder vs properties values + builder.filterLogger = builder.filterLogger == null ? Logger.getLogger(filterLoggerName) : builder.filterLogger; + builder.verbosity = builder.verbosity == null ? filterVerbosity : builder.verbosity; + builder.maxEntitySize = builder.maxEntitySize == null ? filterMaxEntitySize : builder.maxEntitySize; + builder.level = builder.level == null ? loggerLevel : builder.level; + builder.separator = builder.separator == null ? filterSeparator : builder.separator; + + return builder; } /** @@ -313,4 +364,45 @@ public enum Verbosity { */ PAYLOAD_ANY } -} + + /** + * Builder class for logging feature configuration. Accepts parameters for the filter logger, verbosity, max + * entity size, level, and separator. + */ + public static class LoggingFeatureBuilder { + + Logger filterLogger; + Verbosity verbosity; + Integer maxEntitySize; + Level level; + String separator; + + public LoggingFeatureBuilder() { + + } + public LoggingFeatureBuilder withLogger(Logger logger) { + this.filterLogger = logger; + return this; + } + public LoggingFeatureBuilder verbosity(Verbosity verbosity) { + this.verbosity = verbosity; + return this; + } + public LoggingFeatureBuilder maxEntitySize(Integer maxEntitySize) { + this.maxEntitySize = maxEntitySize; + return this; + } + public LoggingFeatureBuilder level(Level level) { + this.level = level; + return this; + } + public LoggingFeatureBuilder separator(String separator) { + this.separator = separator; + return this; + } + + public LoggingFeature build() { + return new LoggingFeature(this); + } + } +} \ No newline at end of file diff --git a/core-common/src/main/java/org/glassfish/jersey/logging/LoggingFeatureAutoDiscoverable.java b/core-common/src/main/java/org/glassfish/jersey/logging/LoggingFeatureAutoDiscoverable.java index 205ed08b5f..01e61a5e9d 100644 --- a/core-common/src/main/java/org/glassfish/jersey/logging/LoggingFeatureAutoDiscoverable.java +++ b/core-common/src/main/java/org/glassfish/jersey/logging/LoggingFeatureAutoDiscoverable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2019 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2021 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 @@ -34,6 +34,9 @@ import static org.glassfish.jersey.logging.LoggingFeature.LOGGING_FEATURE_MAX_ENTITY_SIZE; import static org.glassfish.jersey.logging.LoggingFeature.LOGGING_FEATURE_MAX_ENTITY_SIZE_CLIENT; import static org.glassfish.jersey.logging.LoggingFeature.LOGGING_FEATURE_MAX_ENTITY_SIZE_SERVER; +import static org.glassfish.jersey.logging.LoggingFeature.LOGGING_FEATURE_SEPARATOR; +import static org.glassfish.jersey.logging.LoggingFeature.LOGGING_FEATURE_SEPARATOR_CLIENT; +import static org.glassfish.jersey.logging.LoggingFeature.LOGGING_FEATURE_SEPARATOR_SERVER; import static org.glassfish.jersey.logging.LoggingFeature.LOGGING_FEATURE_VERBOSITY; import static org.glassfish.jersey.logging.LoggingFeature.LOGGING_FEATURE_VERBOSITY_CLIENT; import static org.glassfish.jersey.logging.LoggingFeature.LOGGING_FEATURE_VERBOSITY_SERVER; @@ -71,20 +74,23 @@ private boolean commonPropertyConfigured(Map properties) { return properties.containsKey(LOGGING_FEATURE_LOGGER_NAME) || properties.containsKey(LOGGING_FEATURE_LOGGER_LEVEL) || properties.containsKey(LOGGING_FEATURE_VERBOSITY) - || properties.containsKey(LOGGING_FEATURE_MAX_ENTITY_SIZE); + || properties.containsKey(LOGGING_FEATURE_MAX_ENTITY_SIZE) + || properties.containsKey(LOGGING_FEATURE_SEPARATOR); } private boolean clientConfigured(Map properties) { return properties.containsKey(LOGGING_FEATURE_LOGGER_NAME_CLIENT) || properties.containsKey(LOGGING_FEATURE_LOGGER_LEVEL_CLIENT) || properties.containsKey(LOGGING_FEATURE_VERBOSITY_CLIENT) - || properties.containsKey(LOGGING_FEATURE_MAX_ENTITY_SIZE_CLIENT); + || properties.containsKey(LOGGING_FEATURE_MAX_ENTITY_SIZE_CLIENT) + || properties.containsKey(LOGGING_FEATURE_SEPARATOR_CLIENT); } private boolean serverConfigured(Map properties) { return properties.containsKey(LOGGING_FEATURE_LOGGER_NAME_SERVER) || properties.containsKey(LOGGING_FEATURE_LOGGER_LEVEL_SERVER) || properties.containsKey(LOGGING_FEATURE_VERBOSITY_SERVER) - || properties.containsKey(LOGGING_FEATURE_MAX_ENTITY_SIZE_SERVER); + || properties.containsKey(LOGGING_FEATURE_MAX_ENTITY_SIZE_SERVER) + || properties.containsKey(LOGGING_FEATURE_SEPARATOR_SERVER); } } diff --git a/core-common/src/main/java/org/glassfish/jersey/logging/LoggingInterceptor.java b/core-common/src/main/java/org/glassfish/jersey/logging/LoggingInterceptor.java index 7ad26ec5d6..601d6b2828 100644 --- a/core-common/src/main/java/org/glassfish/jersey/logging/LoggingInterceptor.java +++ b/core-common/src/main/java/org/glassfish/jersey/logging/LoggingInterceptor.java @@ -103,23 +103,28 @@ public int compare(final Map.Entry<String, List<String>> o1, final Map.Entry<Str final AtomicLong _id = new AtomicLong(0); final Verbosity verbosity; final int maxEntitySize; + final String separator; /** - * Creates a logging filter with custom logger and entity logging turned on, but potentially limiting the size - * of entity to be buffered and logged. + * Creates a logging filter using builder instance with custom logger and entity logging turned on, + * but potentially limiting the size of entity to be buffered and logged. * - * @param logger the logger to log messages to. - * @param level level at which the messages will be logged. - * @param verbosity verbosity of the logged messages. See {@link Verbosity}. - * @param maxEntitySize maximum number of entity bytes to be logged (and buffered) - if the entity is larger, + * @param builder loggingFeatureBuilder which contains values for: + * logger the logger to log messages to. + * level level at which the messages will be logged. + * verbosity verbosity of the logged messages. See {@link Verbosity}. + * maxEntitySize maximum number of entity bytes to be logged (and buffered) - if the entity is larger, * logging filter will print (and buffer in memory) only the specified number of bytes * and print "...more..." string at the end. Negative values are interpreted as zero. + * separator delimiter for particular log lines. Default is Linux new line delimiter */ - LoggingInterceptor(final Logger logger, final Level level, final Verbosity verbosity, final int maxEntitySize) { - this.logger = logger; - this.level = level; - this.verbosity = verbosity; - this.maxEntitySize = Math.max(0, maxEntitySize); + + LoggingInterceptor(LoggingFeature.LoggingFeatureBuilder builder) { + this.logger = builder.filterLogger; + this.level = builder.level; + this.verbosity = builder.verbosity; + this.maxEntitySize = Math.max(0, builder.maxEntitySize); + this.separator = builder.separator; } /** @@ -142,18 +147,18 @@ void printRequestLine(final StringBuilder b, final String note, final long id, f prefixId(b, id).append(NOTIFICATION_PREFIX) .append(note) .append(" on thread ").append(Thread.currentThread().getName()) - .append("\n"); + .append(separator); prefixId(b, id).append(REQUEST_PREFIX).append(method).append(" ") - .append(uri.toASCIIString()).append("\n"); + .append(uri.toASCIIString()).append(separator); } void printResponseLine(final StringBuilder b, final String note, final long id, final int status) { prefixId(b, id).append(NOTIFICATION_PREFIX) .append(note) - .append(" on thread ").append(Thread.currentThread().getName()).append("\n"); + .append(" on thread ").append(Thread.currentThread().getName()).append(separator); prefixId(b, id).append(RESPONSE_PREFIX) .append(Integer.toString(status)) - .append("\n"); + .append(separator); } void printPrefixedHeaders(final StringBuilder b, @@ -165,7 +170,7 @@ void printPrefixedHeaders(final StringBuilder b, final String header = headerEntry.getKey(); if (val.size() == 1) { - prefixId(b, id).append(prefix).append(header).append(": ").append(val.get(0)).append("\n"); + prefixId(b, id).append(prefix).append(header).append(": ").append(val.get(0)).append(separator); } else { final StringBuilder sb = new StringBuilder(); boolean add = false; @@ -176,7 +181,7 @@ void printPrefixedHeaders(final StringBuilder b, add = true; sb.append(s); } - prefixId(b, id).append(prefix).append(header).append(": ").append(sb.toString()).append("\n"); + prefixId(b, id).append(prefix).append(header).append(": ").append(sb.toString()).append(separator); } } } diff --git a/core-common/src/main/java/org/glassfish/jersey/logging/ServerLoggingFilter.java b/core-common/src/main/java/org/glassfish/jersey/logging/ServerLoggingFilter.java index 8405edff43..b1c2c7b393 100644 --- a/core-common/src/main/java/org/glassfish/jersey/logging/ServerLoggingFilter.java +++ b/core-common/src/main/java/org/glassfish/jersey/logging/ServerLoggingFilter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2019 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2021 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 @@ -53,18 +53,20 @@ final class ServerLoggingFilter extends LoggingInterceptor implements ContainerRequestFilter, ContainerResponseFilter { /** - * Create a logging filter with custom logger and custom settings of entity + * Create a logging filter using builder instance with custom logger and custom settings of entity * logging. * - * @param logger the logger to log messages to. - * @param level level at which the messages will be logged. - * @param verbosity verbosity of the logged messages. See {@link Verbosity}. - * @param maxEntitySize maximum number of entity bytes to be logged (and buffered) - if the entity is larger, + * @param builder loggingFeatureBuilder which contains values for: + * logger the logger to log messages to. + * level level at which the messages will be logged. + * verbosity verbosity of the logged messages. See {@link Verbosity}. + * maxEntitySize maximum number of entity bytes to be logged (and buffered) - if the entity is larger, * logging filter will print (and buffer in memory) only the specified number of bytes * and print "...more..." string at the end. Negative values are interpreted as zero. + * separator delimiter for particular log lines. Default is Linux new line delimiter */ - public ServerLoggingFilter(final Logger logger, final Level level, final Verbosity verbosity, final int maxEntitySize) { - super(logger, level, verbosity, maxEntitySize); + public ServerLoggingFilter(final LoggingFeature.LoggingFeatureBuilder builder) { + super(builder); } @Override diff --git a/core-common/src/test/java/org/glassfish/jersey/logging/LoggingInterceptorTest.java b/core-common/src/test/java/org/glassfish/jersey/logging/LoggingInterceptorTest.java index 55162737e4..c19cb1934e 100644 --- a/core-common/src/test/java/org/glassfish/jersey/logging/LoggingInterceptorTest.java +++ b/core-common/src/test/java/org/glassfish/jersey/logging/LoggingInterceptorTest.java @@ -126,7 +126,7 @@ public void testVerbosityHeadersPrintBinaryEntity() { @Test public void testLogInboundEntityMockedStream() throws Exception { int maxEntitySize = 20; - LoggingInterceptor loggingInterceptor = new LoggingInterceptor(null, null, null, maxEntitySize) {}; + LoggingInterceptor loggingInterceptor = new LoggingInterceptor(LoggingFeature.builder().maxEntitySize(maxEntitySize)) {}; StringBuilder buffer = new StringBuilder(); InputStream stream = mock(InputStream.class); @@ -162,7 +162,7 @@ public void testLogInboundEntityRealStream() throws Exception { int maxEntitySize = 2000; String inputString = getRandomString(maxEntitySize * 2); - LoggingInterceptor loggingInterceptor = new LoggingInterceptor(null, null, null, maxEntitySize) {}; + LoggingInterceptor loggingInterceptor = new LoggingInterceptor(LoggingFeature.builder().maxEntitySize(maxEntitySize)) {}; StringBuilder buffer = new StringBuilder(); InputStream stream = new ByteArrayInputStream(inputString.getBytes()); diff --git a/docs/src/main/docbook/appendix-properties.xml b/docs/src/main/docbook/appendix-properties.xml index 3eecfaff0c..6011f89ed5 100644 --- a/docs/src/main/docbook/appendix-properties.xml +++ b/docs/src/main/docbook/appendix-properties.xml @@ -143,6 +143,17 @@ See <link linkend="logging.xml">logging</link> chapter for more information. </entry> </row> + <row> + <entry>&jersey.logging.LoggingFeature.LOGGING_FEATURE_SEPARATOR; + </entry> + <entry> + <literal>jersey.config.logging.entity.separator</literal> + </entry> + <entry> + Custom logging delimiter for new lines separation. + See <link linkend="logging.xml">logging</link> chapter for more information. + </entry> + </row> </tbody> </tgroup> </table> @@ -584,6 +595,17 @@ See <link linkend="logging.xml">logging</link> chapter for more information. </entry> </row> + <row> + <entry>&jersey.logging.LoggingFeature.LOGGING_FEATURE_SEPARATOR_SERVER; + </entry> + <entry> + <literal>jersey.config.server.logging.entity.separator</literal> + </entry> + <entry> + Custom delimiter for new lines separation. + See <link linkend="logging.xml">logging</link> chapter for more information. + </entry> + </row> </tbody> </tgroup> </table> @@ -911,6 +933,17 @@ See <link linkend="logging_chapter">logging</link> chapter for more information. </entry> </row> + <row> + <entry>&jersey.logging.LoggingFeature.LOGGING_FEATURE_SEPARATOR_CLIENT; + </entry> + <entry> + <literal>jersey.config.client.logging.entity.separator</literal> + </entry> + <entry> + New line delimiter property (client side). + See <link linkend="logging_chapter">logging</link> chapter for more information. + </entry> + </row> </tbody> </tgroup> </table> diff --git a/docs/src/main/docbook/jersey.ent b/docs/src/main/docbook/jersey.ent index 9ebf7c2d4d..fd87f28186 100644 --- a/docs/src/main/docbook/jersey.ent +++ b/docs/src/main/docbook/jersey.ent @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="iso-8859-1" ?> <!-- - Copyright (c) 2010, 2020 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2010, 2021 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 @@ -409,14 +409,17 @@ <!ENTITY jersey.logging.LoggingFeature.LOGGING_FEATURE_LOGGER_LEVEL "<link xlink:href='&jersey.javadoc.uri.prefix;/logging/LoggingFeature.html#LOGGING_FEATURE_LOGGER_LEVEL'>LoggingFeature.LOGGING_FEATURE_LOGGER_LEVEL</link>"> <!ENTITY jersey.logging.LoggingFeature.LOGGING_FEATURE_VERBOSITY "<link xlink:href='&jersey.javadoc.uri.prefix;/logging/LoggingFeature.html#LOGGING_FEATURE_VERBOSITY'>LoggingFeature.LOGGING_FEATURE_VERBOSITY</link>"> <!ENTITY jersey.logging.LoggingFeature.LOGGING_FEATURE_MAX_ENTITY_SIZE "<link xlink:href='&jersey.javadoc.uri.prefix;/logging/LoggingFeature.html#LOGGING_FEATURE_MAX_ENTITY_SIZE'>LoggingFeature.LOGGING_FEATURE_MAX_ENTITY_SIZE</link>"> +<!ENTITY jersey.logging.LoggingFeature.LOGGING_FEATURE_SEPARATOR "<link xlink:href='&jersey.javadoc.uri.prefix;/logging/LoggingFeature.html#LOGGING_FEATURE_SEPARATOR'>LoggingFeature.LOGGING_FEATURE_SEPARATOR</link>"> <!ENTITY jersey.logging.LoggingFeature.LOGGING_FEATURE_LOGGER_NAME_CLIENT "<link xlink:href='&jersey.javadoc.uri.prefix;/logging/LoggingFeature.html#LOGGING_FEATURE_LOGGER_NAME_CLIENT'>LoggingFeature.LOGGING_FEATURE_LOGGER_NAME_CLIENT</link>"> <!ENTITY jersey.logging.LoggingFeature.LOGGING_FEATURE_LOGGER_LEVEL_CLIENT "<link xlink:href='&jersey.javadoc.uri.prefix;/logging/LoggingFeature.html#LOGGING_FEATURE_LOGGER_LEVEL_CLIENT'>LoggingFeature.LOGGING_FEATURE_LOGGER_LEVEL_CLIENT</link>"> <!ENTITY jersey.logging.LoggingFeature.LOGGING_FEATURE_VERBOSITY_CLIENT "<link xlink:href='&jersey.javadoc.uri.prefix;/logging/LoggingFeature.html#LOGGING_FEATURE_VERBOSITY_CLIENT'>LoggingFeature.LOGGING_FEATURE_VERBOSITY_CLIENT</link>"> <!ENTITY jersey.logging.LoggingFeature.LOGGING_FEATURE_MAX_ENTITY_SIZE_CLIENT "<link xlink:href='&jersey.javadoc.uri.prefix;/logging/LoggingFeature.html#LOGGING_FEATURE_MAX_ENTITY_SIZE_CLIENT'>LoggingFeature.LOGGING_FEATURE_MAX_ENTITY_SIZE_CLIENT</link>"> +<!ENTITY jersey.logging.LoggingFeature.LOGGING_FEATURE_SEPARATOR_CLIENT "<link xlink:href='&jersey.javadoc.uri.prefix;/logging/LoggingFeature.html#LOGGING_FEATURE_MAX_ENTITY_SIZE_CLIENT'>LoggingFeature.LOGGING_FEATURE_SEPARATOR_CLIENT</link>"> <!ENTITY jersey.logging.LoggingFeature.LOGGING_FEATURE_LOGGER_NAME_SERVER "<link xlink:href='&jersey.javadoc.uri.prefix;/logging/LoggingFeature.html#LOGGING_FEATURE_LOGGER_NAME_SERVER'>LoggingFeature.LOGGING_FEATURE_LOGGER_NAME_SERVER</link>"> <!ENTITY jersey.logging.LoggingFeature.LOGGING_FEATURE_LOGGER_LEVEL_SERVER "<link xlink:href='&jersey.javadoc.uri.prefix;/logging/LoggingFeature.html#LOGGING_FEATURE_LOGGER_LEVEL_SERVER'>LoggingFeature.LOGGING_FEATURE_LOGGER_LEVEL_SERVER</link>"> <!ENTITY jersey.logging.LoggingFeature.LOGGING_FEATURE_VERBOSITY_SERVER "<link xlink:href='&jersey.javadoc.uri.prefix;/logging/LoggingFeature.html#LOGGING_FEATURE_VERBOSITY_SERVER'>LoggingFeature.LOGGING_FEATURE_VERBOSITY_SERVER</link>"> <!ENTITY jersey.logging.LoggingFeature.LOGGING_FEATURE_MAX_ENTITY_SIZE_SERVER "<link xlink:href='&jersey.javadoc.uri.prefix;/logging/LoggingFeature.html#LOGGING_FEATURE_MAX_ENTITY_SIZE_SERVER'>LoggingFeature.LOGGING_FEATURE_MAX_ENTITY_SIZE_SERVER</link>"> +<!ENTITY jersey.logging.LoggingFeature.LOGGING_FEATURE_SEPARATOR_SERVER "<link xlink:href='&jersey.javadoc.uri.prefix;/logging/LoggingFeature.html#LOGGING_FEATURE_MAX_ENTITY_SIZE_SERVER'>LoggingFeature.LOGGING_FEATURE_SEPARATOR_SERVER</link>"> <!ENTITY jersey.logging.LoggingFeature.Verbosity "<link xlink:href='&jersey.javadoc.uri.prefix;/logging/LoggingFeature.Verbosity.html'>LoggingFeature.Verbosity</link>"> <!ENTITY jersey.logging.LoggingFeature.Verbosity.HEADERS_ONLY "<link xlink:href='&jersey.javadoc.uri.prefix;/logging/LoggingFeature.Verbosity.html#HEADERS_ONLY'>LoggingFeature.Verbosity.HEADERS_ONLY</link>"> <!ENTITY jersey.logging.LoggingFeature.Verbosity.PAYLOAD_ANY "<link xlink:href='&jersey.javadoc.uri.prefix;/logging/LoggingFeature.Verbosity.html#PAYLOAD_ANY'>LoggingFeature.Verbosity.PAYLOAD_ANY</link>"> @@ -892,14 +895,17 @@ <!ENTITY lit.jersey.logging.LoggingFeature.LOGGING_FEATURE_LOGGER_LEVEL "<literal>LoggingFeature.LOGGING_FEATURE_LOGGER_LEVEL</literal>"> <!ENTITY lit.jersey.logging.LoggingFeature.LOGGING_FEATURE_VERBOSITY "<literal>LoggingFeature.LOGGING_FEATURE_VERBOSITY</literal>"> <!ENTITY lit.jersey.logging.LoggingFeature.LOGGING_FEATURE_MAX_ENTITY_SIZE "<literal>LoggingFeature.LOGGING_FEATURE_MAX_ENTITY_SIZE</literal>"> +<!ENTITY lit.jersey.logging.LoggingFeature.LOGGING_FEATURE_SEPARATOR "<literal>LoggingFeature.LOGGING_FEATURE_SEPARATOR</literal>"> <!ENTITY lit.jersey.logging.LoggingFeature.LOGGING_FEATURE_LOGGER_NAME_CLIENT "<literal>LoggingFeature.LOGGING_FEATURE_LOGGER_NAME_CLIENT</literal>"> <!ENTITY lit.jersey.logging.LoggingFeature.LOGGING_FEATURE_LOGGER_LEVEL_CLIENT "<literal>LoggingFeature.LOGGING_FEATURE_LOGGER_LEVEL_CLIENT</literal>"> <!ENTITY lit.jersey.logging.LoggingFeature.LOGGING_FEATURE_VERBOSITY_CLIENT "<literal>LoggingFeature.LOGGING_FEATURE_VERBOSITY_CLIENT</literal>"> <!ENTITY lit.jersey.logging.LoggingFeature.LOGGING_FEATURE_MAX_ENTITY_SIZE_CLIENT "<literal>LoggingFeature.LOGGING_FEATURE_MAX_ENTITY_SIZE_CLIENT</literal>"> +<!ENTITY lit.jersey.logging.LoggingFeature.LOGGING_FEATURE_SEPARATOR_CLIENT "<literal>LoggingFeature.LOGGING_FEATURE_SEPARATORE_CLIENT</literal>"> <!ENTITY lit.jersey.logging.LoggingFeature.LOGGING_FEATURE_LOGGER_NAME_SERVER "<literal>LoggingFeature.LOGGING_FEATURE_LOGGER_NAME_SERVER</literal>"> <!ENTITY lit.jersey.logging.LoggingFeature.LOGGING_FEATURE_LOGGER_LEVEL_SERVER "<literal>LoggingFeature.LOGGING_FEATURE_LOGGER_LEVEL_SERVER</literal>"> <!ENTITY lit.jersey.logging.LoggingFeature.LOGGING_FEATURE_VERBOSITY_SERVER "<literal>LoggingFeature.LOGGING_FEATURE_VERBOSITY_SERVER</literal>"> <!ENTITY lit.jersey.logging.LoggingFeature.LOGGING_FEATURE_MAX_ENTITY_SIZE_SERVER "<literal>LoggingFeature.LOGGING_FEATURE_MAX_ENTITY_SIZE_SERVER</literal>"> +<!ENTITY lit.jersey.logging.LoggingFeature.LOGGING_FEATURE_SEPARATOR_SERVER "<literal>LoggingFeature.LOGGING_FEATURE_SEPARATOR_SERVER</literal>"> <!ENTITY lit.jersey.logging.LoggingFeature.Verbosity "<literal>LoggingFeature.Verbosity</literal>"> <!ENTITY lit.jersey.logging.LoggingFeature.Verbosity.HEADERS_ONLY "<literal>LoggingFeature.Verbosity.HEADERS_ONLY</literal>"> <!ENTITY lit.jersey.logging.LoggingFeature.Verbosity.PAYLOAD_ANY "<literal>LoggingFeature.Verbosity.PAYLOAD_ANY</literal>"> @@ -1044,4 +1050,4 @@ <!ENTITY lit.jersey.test.util.LoopBackConnectorProvider "<literal>LoopBackConnectorProvider</literal>"> <!ENTITY lit.jersey.test.util.ContainerRequestBuilder "<literal>ContainerRequestBuilder</literal>"> -<!ENTITY lit.jsonb.Jsonb "<literal>Jsonb</literal>"> \ No newline at end of file +<!ENTITY lit.jsonb.Jsonb "<literal>Jsonb</literal>"> diff --git a/tests/e2e/src/test/java/org/glassfish/jersey/tests/e2e/common/LoggingFeatureTest.java b/tests/e2e/src/test/java/org/glassfish/jersey/tests/e2e/common/LoggingFeatureTest.java index 280e94d251..b85b8dfbd1 100644 --- a/tests/e2e/src/test/java/org/glassfish/jersey/tests/e2e/common/LoggingFeatureTest.java +++ b/tests/e2e/src/test/java/org/glassfish/jersey/tests/e2e/common/LoggingFeatureTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2021 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 @@ -76,6 +76,7 @@ public class LoggingFeatureTest { private static final String BINARY_MEDIA_TYPE = "application/binary"; private static final String TEXT_MEDIA_TYPE = MediaType.TEXT_PLAIN; private static final String ENTITY = "This entity must (not) be logged"; + private static final String SEPARATOR = "!-------!"; @Path("/") public static class MyResource { @@ -245,6 +246,44 @@ public void testPostedEntityLogged() throws Exception { assertThat(getLoggingFilterLogRecord(getLoggedRecords()).get(0).getMessage(), containsString(ENTITY)); } + @Test + public void testLoggingFeatureBuilderSeparator() { + final Response response = target("/text") + .register(LoggingFeature + .builder() + .withLogger(Logger.getLogger(LOGGER_NAME)) + .verbosity(LoggingFeature.Verbosity.PAYLOAD_ANY) + .separator(SEPARATOR) + .build() + ).request() + .post(Entity.text(ENTITY)); + + // Correct response status. + assertThat(response.getStatus(), is(Response.Status.OK.getStatusCode())); + // Check logs for proper separator. + final LogRecord record = getLoggingFilterResponseLogRecord(getLoggedRecords()); + assertThat(record.getMessage(), containsString(SEPARATOR)); + + } + + @Test + public void testLoggingFeatureBuilderProperty() { + final Response response = target("/text") + .register(LoggingFeature + .builder() + .withLogger(Logger.getLogger(LOGGER_NAME)) + .build() + ).property(LoggingFeature.LOGGING_FEATURE_SEPARATOR, SEPARATOR) + .request() + .post(Entity.text(ENTITY)); + + // Correct response status. + assertThat(response.getStatus(), is(Response.Status.OK.getStatusCode())); + // Check logs for proper separator. + final LogRecord record = getLoggingFilterResponseLogRecord(getLoggedRecords()); + assertThat(record.getMessage(), containsString(SEPARATOR)); + } + } /** From 73206d9f963014fe4be5d4ab97bd78f69792d08a Mon Sep 17 00:00:00 2001 From: jansupol <jan.supol@oracle.com> Date: Wed, 24 Mar 2021 22:31:30 +0100 Subject: [PATCH 4/9] Adopt ASM 9.1 to support JDK 17 Signed-off-by: jansupol <jan.supol@oracle.com> --- .../org/objectweb/asm/AnnotationVisitor.java | 4 ++-- .../org/objectweb/asm/ClassReader.java | 24 ++++++++++++++----- .../repackaged/org/objectweb/asm/Opcodes.java | 5 ++-- .../scanning/AnnotationAcceptingListener.java | 4 ++-- pom.xml | 2 +- 5 files changed, 26 insertions(+), 13 deletions(-) diff --git a/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/AnnotationVisitor.java b/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/AnnotationVisitor.java index 33293bb473..8ca2039014 100644 --- a/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/AnnotationVisitor.java +++ b/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/AnnotationVisitor.java @@ -131,9 +131,9 @@ public AnnotationVisitor visitAnnotation(final String name, final String descrip } /** - * Visits an array value of the annotation. Note that arrays of primitive types (such as byte, + * Visits an array value of the annotation. Note that arrays of primitive values (such as byte, * boolean, short, char, int, long, float or double) can be passed as value to {@link #visit - * visit}. This is what {@link ClassReader} does. + * visit}. This is what {@link ClassReader} does for non empty arrays of primitive values. * * @param name the value name. * @return a visitor to visit the actual array value elements, or {@literal null} if this visitor diff --git a/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/ClassReader.java b/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/ClassReader.java index 25015fdd18..a46fdad3e1 100644 --- a/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/ClassReader.java +++ b/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/ClassReader.java @@ -100,8 +100,10 @@ public class ClassReader { @Deprecated // DontCheck(MemberName): can't be renamed (for backward binary compatibility). public final byte[] b; + /** The offset in bytes of the ClassFile's access_flags field. */ public final int header; + /** * A byte array containing the JVMS ClassFile structure to be parsed. <i>The content of this array * must not be modified. This field is intended for {@link Attribute} sub classes, and is normally @@ -112,6 +114,7 @@ public class ClassReader { * ClassFile element offsets within this byte array. */ final byte[] classFileBuffer; + /** * The offset in bytes, in {@link #classFileBuffer}, of each cp_info entry of the ClassFile's * constant_pool array, <i>plus one</i>. In other words, the offset of constant pool entry i is @@ -119,16 +122,19 @@ public class ClassReader { * 1]. */ private final int[] cpInfoOffsets; + /** * The String objects corresponding to the CONSTANT_Utf8 constant pool items. This cache avoids * multiple parsing of a given CONSTANT_Utf8 constant pool item. */ private final String[] constantUtf8Values; + /** * The ConstantDynamic objects corresponding to the CONSTANT_Dynamic constant pool items. This * cache avoids multiple parsing of a given CONSTANT_Dynamic constant pool item. */ private final ConstantDynamic[] constantDynamicValues; + /** * The start offsets in {@link #classFileBuffer} of each element of the bootstrap_methods array * (in the BootstrapMethods attribute). @@ -137,6 +143,7 @@ public class ClassReader { * 4.7.23</a> */ private final int[] bootstrapMethodOffsets; + /** * A conservative estimate of the maximum length of the strings contained in the constant pool of * the class. @@ -184,7 +191,7 @@ public ClassReader( this.b = classFileBuffer; // Check the class' major_version. This field is after the magic and minor_version fields, which // use 4 and 2 bytes respectively. - if (checkClassVersion && readShort(classFileOffset + 6) > Opcodes.V16) { + if (checkClassVersion && readShort(classFileOffset + 6) > Opcodes.V17) { throw new IllegalArgumentException( "Unsupported class file major version " + readShort(classFileOffset + 6)); } @@ -499,6 +506,9 @@ public void accept( } else if (Constants.SYNTHETIC.equals(attributeName)) { accessFlags |= Opcodes.ACC_SYNTHETIC; } else if (Constants.SOURCE_DEBUG_EXTENSION.equals(attributeName)) { + if (attributeLength > classFileBuffer.length - currentAttributeOffset) { + throw new IllegalArgumentException(); + } sourceDebugExtension = readUtf(currentAttributeOffset, attributeLength, new char[attributeLength]); } else if (Constants.RUNTIME_INVISIBLE_ANNOTATIONS.equals(attributeName)) { @@ -1509,6 +1519,9 @@ private void readCode( final int maxLocals = readUnsignedShort(currentOffset + 2); final int codeLength = readInt(currentOffset + 4); currentOffset += 8; + if (codeLength > classFileBuffer.length - currentOffset) { + throw new IllegalArgumentException(); + } // Read the bytecode 'code' array to create a label for each referenced instruction. final int bytecodeStartOffset = currentOffset; @@ -3438,7 +3451,6 @@ final int getFirstAttributeOffset() { private int[] readBootstrapMethodsAttribute(final int maxStringLength) { char[] charBuffer = new char[maxStringLength]; int currentAttributeOffset = getFirstAttributeOffset(); - int[] currentBootstrapMethodOffsets = null; for (int i = readUnsignedShort(currentAttributeOffset - 2); i > 0; --i) { // Read the attribute_info's attribute_name and attribute_length fields. String attributeName = readUTF8(currentAttributeOffset, charBuffer); @@ -3446,17 +3458,17 @@ private int[] readBootstrapMethodsAttribute(final int maxStringLength) { currentAttributeOffset += 6; if (Constants.BOOTSTRAP_METHODS.equals(attributeName)) { // Read the num_bootstrap_methods field and create an array of this size. - currentBootstrapMethodOffsets = new int[readUnsignedShort(currentAttributeOffset)]; + int[] result = new int[readUnsignedShort(currentAttributeOffset)]; // Compute and store the offset of each 'bootstrap_methods' array field entry. int currentBootstrapMethodOffset = currentAttributeOffset + 2; - for (int j = 0; j < currentBootstrapMethodOffsets.length; ++j) { - currentBootstrapMethodOffsets[j] = currentBootstrapMethodOffset; + for (int j = 0; j < result.length; ++j) { + result[j] = currentBootstrapMethodOffset; // Skip the bootstrap_method_ref and num_bootstrap_arguments fields (2 bytes each), // as well as the bootstrap_arguments array field (of size num_bootstrap_arguments * 2). currentBootstrapMethodOffset += 4 + readUnsignedShort(currentBootstrapMethodOffset + 2) * 2; } - return currentBootstrapMethodOffsets; + return result; } currentAttributeOffset += attributeLength; } diff --git a/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/Opcodes.java b/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/Opcodes.java index f9beb52256..9e9bdd770d 100644 --- a/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/Opcodes.java +++ b/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/Opcodes.java @@ -133,7 +133,7 @@ public interface Opcodes { * <pre> * public class StuffVisitor { * @Deprecated public void visitOldStuff(int arg, ...) { - * visitNewStuf(arg | SOURCE_DEPRECATED, ...); + * visitNewStuff(arg | SOURCE_DEPRECATED, ...); * } * public void visitNewStuff(int argAndSource...) { * if ((argAndSource & SOURCE_DEPRECATED) == 0) { @@ -155,7 +155,7 @@ public interface Opcodes { * <p>and there are two cases: * * <ul> - * <li>call visitOldSuff: in the call to super.visitOldStuff, the source is set to + * <li>call visitOldStuff: in the call to super.visitOldStuff, the source is set to * SOURCE_DEPRECATED and visitNewStuff is called. Here 'do stuff' is run because the source * was previously set to SOURCE_DEPRECATED, and execution eventually returns to * UserStuffVisitor.visitOldStuff, where 'do user stuff' is run. @@ -282,6 +282,7 @@ public interface Opcodes { int V14 = 0 << 16 | 58; int V15 = 0 << 16 | 59; int V16 = 0 << 16 | 60; + int V17 = 0 << 16 | 61; /** * Version flag indicating that the class is using 'preview' features. diff --git a/core-server/src/main/java/org/glassfish/jersey/server/internal/scanning/AnnotationAcceptingListener.java b/core-server/src/main/java/org/glassfish/jersey/server/internal/scanning/AnnotationAcceptingListener.java index 5efc6bae45..96e840c1c2 100644 --- a/core-server/src/main/java/org/glassfish/jersey/server/internal/scanning/AnnotationAcceptingListener.java +++ b/core-server/src/main/java/org/glassfish/jersey/server/internal/scanning/AnnotationAcceptingListener.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2021 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 @@ -303,7 +303,7 @@ private Class getClassForName(final String className) { private static class ClassReaderWrapper { private static final Logger LOGGER = Logger.getLogger(ClassReader.class.getName()); - private static final int WARN_VERSION = Opcodes.V16; + private static final int WARN_VERSION = Opcodes.V17; private static final int INPUT_STREAM_DATA_CHUNK_SIZE = 4096; private final byte[] b; diff --git a/pom.xml b/pom.xml index 9baf7e603e..bc916373b6 100644 --- a/pom.xml +++ b/pom.xml @@ -2074,7 +2074,7 @@ <jersey.version>${project.version}</jersey.version> <!-- asm is now source integrated - keeping this property to see the version --> <!-- see core-server/src/main/java/jersey/repackaged/asm/.. --> - <asm.version>9.0</asm.version> + <asm.version>9.1</asm.version> <bnd.plugin.version>2.3.6</bnd.plugin.version> <cdi.api.version>1.1</cdi.api.version> <commons-lang3.version>3.3.2</commons-lang3.version> From d2b7b65b8f9baa8ed3069f083890badb63911dd9 Mon Sep 17 00:00:00 2001 From: jansupol <jan.supol@oracle.com> Date: Tue, 6 Apr 2021 18:13:10 +0200 Subject: [PATCH 5/9] Lazy synchronized SSL Context initialization in the HttpUrlConnector Signed-off-by: jansupol <jan.supol@oracle.com> --- .../glassfish/jersey/client/internal/HttpUrlConnector.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/core-client/src/main/java/org/glassfish/jersey/client/internal/HttpUrlConnector.java b/core-client/src/main/java/org/glassfish/jersey/client/internal/HttpUrlConnector.java index 72bceec3ad..21456b9c2e 100644 --- a/core-client/src/main/java/org/glassfish/jersey/client/internal/HttpUrlConnector.java +++ b/core-client/src/main/java/org/glassfish/jersey/client/internal/HttpUrlConnector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2021 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 @@ -73,7 +73,8 @@ public class HttpUrlConnector implements Connector { private static final String ALLOW_RESTRICTED_HEADERS_SYSTEM_PROPERTY = "sun.net.http.allowRestrictedHeaders"; // Avoid multi-thread uses of HttpsURLConnection.getDefaultSSLSocketFactory() because it does not implement a // proper lazy-initialization. See https://github.com/jersey/jersey/issues/3293 - private static final SSLSocketFactory DEFAULT_SSL_SOCKET_FACTORY = HttpsURLConnection.getDefaultSSLSocketFactory(); + private static final LazyValue<SSLSocketFactory> DEFAULT_SSL_SOCKET_FACTORY = + Values.lazy((Value<SSLSocketFactory>) () -> HttpsURLConnection.getDefaultSSLSocketFactory()); // The list of restricted headers is extracted from sun.net.www.protocol.http.HttpURLConnection private static final String[] restrictedHeaders = { "Access-Control-Request-Headers", @@ -305,7 +306,7 @@ protected void secureConnection(final JerseyClient client, final HttpURLConnecti suc.setHostnameVerifier(verifier); } - if (DEFAULT_SSL_SOCKET_FACTORY == suc.getSSLSocketFactory()) { + if (DEFAULT_SSL_SOCKET_FACTORY.get() == suc.getSSLSocketFactory()) { // indicates that the custom socket factory was not set suc.setSSLSocketFactory(sslSocketFactory.get()); } From 66aeadd992e5649f511f2c6cbe7eddf8e923d0de Mon Sep 17 00:00:00 2001 From: jansupol <jan.supol@oracle.com> Date: Tue, 6 Apr 2021 15:44:27 +0200 Subject: [PATCH 6/9] Replace null Configuration in ContainerRequest with an empty instance to prevent possible NPE Signed-off-by: jansupol <jan.supol@oracle.com> --- .../glassfish/jersey/server/ContainerRequest.java | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/core-server/src/main/java/org/glassfish/jersey/server/ContainerRequest.java b/core-server/src/main/java/org/glassfish/jersey/server/ContainerRequest.java index d67e8e7419..7823668fbf 100644 --- a/core-server/src/main/java/org/glassfish/jersey/server/ContainerRequest.java +++ b/core-server/src/main/java/org/glassfish/jersey/server/ContainerRequest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2021 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 @@ -31,6 +31,7 @@ import java.util.function.Function; import java.util.stream.Collectors; +import javax.ws.rs.RuntimeType; import javax.ws.rs.container.ContainerRequestContext; import javax.ws.rs.container.ContainerRequestFilter; import javax.ws.rs.container.ContainerResponseFilter; @@ -63,6 +64,8 @@ import org.glassfish.jersey.message.internal.OutboundJaxrsResponse; import org.glassfish.jersey.message.internal.TracingAwarePropertiesDelegate; import org.glassfish.jersey.message.internal.VariantSelector; +import org.glassfish.jersey.model.internal.CommonConfig; +import org.glassfish.jersey.model.internal.ComponentBag; import org.glassfish.jersey.model.internal.RankedProvider; import org.glassfish.jersey.process.Inflector; import org.glassfish.jersey.server.internal.LocalizationMessages; @@ -119,7 +122,7 @@ public class ContainerRequest extends InboundMessageContext // True if the request is used in the response processing phase (for example in ContainerResponseFilter) private boolean inResponseProcessingPhase; // lazy PropertiesResolver - private LazyValue<PropertiesResolver> propertiesResolver = Values.lazy( + private final LazyValue<PropertiesResolver> propertiesResolver = Values.lazy( (Value<PropertiesResolver>) () -> PropertiesResolver.create(getConfiguration(), getPropertiesDelegate()) ); @@ -188,7 +191,12 @@ public ContainerRequest( final String httpMethod, final SecurityContext securityContext, final PropertiesDelegate propertiesDelegate) { - this(baseUri, requestUri, httpMethod, securityContext, propertiesDelegate, (Configuration) null); + this(baseUri, requestUri, httpMethod, securityContext, propertiesDelegate, + new CommonConfig(RuntimeType.SERVER, ComponentBag.EXCLUDE_EMPTY) { + { + this.property(ContainerRequest.class.getName(), Deprecated.class.getSimpleName()); + } + }); } /** From 339e30a88127a76bb56a80d7008f353200b32050 Mon Sep 17 00:00:00 2001 From: jansupol <jan.supol@oracle.com> Date: Tue, 30 Mar 2021 14:20:07 +0200 Subject: [PATCH 7/9] Adopted Jackson 2.12.2. No change in repackaged Jackson. Signed-off-by: jansupol <jan.supol@oracle.com> --- pom.xml | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index bc916373b6..0087da9392 100644 --- a/pom.xml +++ b/pom.xml @@ -61,7 +61,7 @@ <developers> <developer> - <name>Roman Grigoriadi</name> + <name>Jorge Bescos Gascon</name> <organization>Oracle Corporation</organization> <organizationUrl>http://www.oracle.com/</organizationUrl> </developer> @@ -74,6 +74,12 @@ <name>Dmitry Kornilov</name> <organization>Oracle Corporation</organization> <organizationUrl>http://www.oracle.com/</organizationUrl> + <url>https://dmitrykornilov.net</url> + </developer> + <developer> + <name>David Kral</name> + <organization>Oracle Corporation</organization> + <organizationUrl>http://www.oracle.com/</organizationUrl> </developer> <developer> <name>Tomas Kraus</name> @@ -2099,7 +2105,7 @@ <hk2.jvnet.osgi.version>org.jvnet.hk2.*;version="[2.5,4)"</hk2.jvnet.osgi.version> <hk2.config.version>5.1.0</hk2.config.version> <httpclient.version>4.5.13</httpclient.version> - <jackson.version>2.11.3</jackson.version> + <jackson.version>2.12.2</jackson.version> <jackson1.version>1.9.13</jackson1.version> <javassist.version>3.25.0-GA</javassist.version> <jboss.logging.version>3.3.0.Final</jboss.logging.version> From 9647ce541718cd0b583ceba1c735a886ec400b78 Mon Sep 17 00:00:00 2001 From: jansupol <jan.supol@oracle.com> Date: Thu, 8 Apr 2021 16:21:33 +0200 Subject: [PATCH 8/9] Uptake Helidon 2.2.1 Signed-off-by: jansupol <jan.supol@oracle.com> --- connectors/helidon-connector/pom.xml | 15 ++------------- .../helidon/connector/sse/EventOutputTest.java | 4 +--- 2 files changed, 3 insertions(+), 16 deletions(-) diff --git a/connectors/helidon-connector/pom.xml b/connectors/helidon-connector/pom.xml index 5d2b443f52..fc138f2a47 100644 --- a/connectors/helidon-connector/pom.xml +++ b/connectors/helidon-connector/pom.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2020 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2020, 2021 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 @@ -34,8 +34,7 @@ <dependency> <groupId>io.helidon.jersey</groupId> <artifactId>helidon-jersey-connector</artifactId> - <!-- Use 2.0.3 when available --> - <version>2.0.2</version> + <version>2.2.1</version> <scope>provided</scope> </dependency> <dependency> @@ -81,16 +80,6 @@ <detectJavaApiLink>false</detectJavaApiLink> </configuration> </plugin> - <plugin> - <!-- See https://github.com/oracle/helidon/issues/2371 --> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-surefire-plugin</artifactId> - <configuration> - <excludes> - <exclude>**/*Test.java</exclude> - </excludes> - </configuration> - </plugin> </plugins> </build> </project> diff --git a/connectors/helidon-connector/src/test/java/org/glassfish/jersey/helidon/connector/sse/EventOutputTest.java b/connectors/helidon-connector/src/test/java/org/glassfish/jersey/helidon/connector/sse/EventOutputTest.java index 31ceb61e8d..5eb76e8e50 100644 --- a/connectors/helidon-connector/src/test/java/org/glassfish/jersey/helidon/connector/sse/EventOutputTest.java +++ b/connectors/helidon-connector/src/test/java/org/glassfish/jersey/helidon/connector/sse/EventOutputTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2021 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 @@ -139,7 +139,6 @@ public EventOutput getCommentsOnlyStream() throws IOException { } @Test - @Ignore //2.0.0-M3 public void testReadSseEventAsPlainString() throws Exception { final Response r = target().path("test/single").request().get(Response.class); assertThat(r.readEntity(String.class), containsString("single")); @@ -189,7 +188,6 @@ public void onEvent(InboundEvent inboundEvent) { } @Test - @Ignore // 2.0.0-M3 public void testReadFromClosedOutput() throws Exception { /** * Need to disable HTTP Keep-Alive to prevent this test from hanging in HttpURLConnection From 5f9510978b1c8077f3ed54cf8cbce0776e64cbba Mon Sep 17 00:00:00 2001 From: Jorge Bescos Gascon <jorge.bescos.gascon@oracle.com> Date: Tue, 2 Mar 2021 15:11:23 +0100 Subject: [PATCH 9/9] ParameterConverter throwing IllegalArgumentException MUST result in 404 Signed-off-by: Jorge Bescos Gascon <jorge.bescos.gascon@oracle.com> --- .../internal/inject/SingleValueExtractor.java | 8 +- .../server/IllegalArgumentExceptionTest.java | 124 ++++++++++++++++++ 2 files changed, 130 insertions(+), 2 deletions(-) create mode 100644 tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/IllegalArgumentExceptionTest.java diff --git a/core-server/src/main/java/org/glassfish/jersey/server/internal/inject/SingleValueExtractor.java b/core-server/src/main/java/org/glassfish/jersey/server/internal/inject/SingleValueExtractor.java index 69431fb157..8eb21d5660 100644 --- a/core-server/src/main/java/org/glassfish/jersey/server/internal/inject/SingleValueExtractor.java +++ b/core-server/src/main/java/org/glassfish/jersey/server/internal/inject/SingleValueExtractor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2019 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2021 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 @@ -62,7 +62,11 @@ public T extract(final MultivaluedMap<String, String> parameters) { } catch (final WebApplicationException | ProcessingException ex) { throw ex; } catch (final IllegalArgumentException ex) { - return defaultValue(); + if (value == null) { + return defaultValue(); + } else { + throw new ExtractorException(ex); + } } catch (final Exception ex) { throw new ExtractorException(ex); } diff --git a/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/IllegalArgumentExceptionTest.java b/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/IllegalArgumentExceptionTest.java new file mode 100644 index 0000000000..3e27023f0c --- /dev/null +++ b/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/IllegalArgumentExceptionTest.java @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2021 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 + * 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.tests.e2e.server; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Type; + +import javax.validation.constraints.NotNull; +import javax.ws.rs.DefaultValue; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.Path; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.Application; +import javax.ws.rs.core.Response; +import javax.ws.rs.ext.ParamConverter; +import javax.ws.rs.ext.ParamConverterProvider; + +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.test.JerseyTest; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +public class IllegalArgumentExceptionTest extends JerseyTest { + + private static final String PARAM_NAME = "paramName"; + + @Override + protected Application configure() { + return new ResourceConfig(TestResource.class, TestParamProvider.class); + } + + @Path("test") + public static class TestResource { + @GET + @Path("1") + public String get1(@QueryParam(PARAM_NAME) CustomObj value) { + return "ok"; + } + @GET + @Path("2") + public String get2(@NotNull @QueryParam(PARAM_NAME) String value) { + return "ok"; + } + @GET + @Path("3") + public String get3(@NotNull @DefaultValue("get3") @QueryParam(PARAM_NAME) CustomObj value) { + return value.value; + } + @GET + @Path("4") + public String get4(@HeaderParam(PARAM_NAME) CustomObj header) { + return "ok"; + } + } + + @Test + public void illegalArgumentExceptionWith404() { + Response response = target().path("test/1").queryParam(PARAM_NAME, 1).request().get(); + assertEquals(404, response.getStatus()); + } + + @Test + public void validationExceptionWith400() { + Response response = target().path("test/2").request().get(); + assertEquals(400, response.getStatus()); + } + + @Test + public void with200() { + Response response = target().path("test/3").request().get(); + assertEquals(200, response.getStatus()); + assertEquals("get3", response.readEntity(String.class)); + } + + @Test + public void validationExceptionHeaderWith400() { + Response response = target().path("test/4").request().header(PARAM_NAME, "1").get(); + assertEquals(400, response.getStatus()); + } + + private static class CustomObj { + private String value; + } + + public static class TestParamProvider implements ParamConverterProvider { + @Override + public <T> ParamConverter<T> getConverter(Class<T> rawType, Type genericType, Annotation[] annotations) { + return (ParamConverter<T>) new ParamConverter<CustomObj>() { + @Override + public CustomObj fromString(String value) { + if ("1".equals(value)) { + throw new IllegalArgumentException("test exception"); + } else if (value != null) { + CustomObj obj = new CustomObj(); + obj.value = value; + return obj; + } else { + return null; + } + } + @Override + public String toString(CustomObj value) { + return null; + } + }; + } + } +}