Merge remote-tracking branch 'origin/master' into 3.x
Signed-off-by: Maxim Nesen <maxim.nesen@oracle.com>
diff --git a/connectors/helidon-connector/pom.xml b/connectors/helidon-connector/pom.xml
index a5f228f..ec4b69a 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>
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 a4d466c..de8edd2 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 @@
}
@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 @@
}
@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
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 4f3349d..67e6d4e 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
@@ -73,7 +73,8 @@
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 @@
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());
}
diff --git a/core-common/pom.xml b/core-common/pom.xml
index 779d972..8d7d508 100644
--- a/core-common/pom.xml
+++ b/core-common/pom.xml
@@ -217,6 +217,11 @@
<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>
<scope>test</scope>
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 d214cfc..00a1968 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, 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
@@ -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 10708a5..f0c3ffd 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, 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
@@ -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 @@
* 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 @@
* 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 @@
* 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 @@
* 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 @@
* 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 (enabled) {
+ context.register(createLoggingFilter(context, context.getConfiguration().getRuntimeType()));
}
- if (context.getConfiguration().getRuntimeType() == RuntimeType.SERVER) {
- ServerLoggingFilter serverClientFilter = (ServerLoggingFilter) createLoggingFilter(context, RuntimeType.SERVER);
- context.register(serverClientFilter);
- enabled = true;
- }
+
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 @@
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 @@
DEFAULT_MAX_ENTITY_SIZE
));
- Level loggerLevel = Level.parse(filterLevel);
+ final 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);
- }
+ //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 @@
*/
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 31fc474..ddf0473 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, 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
@@ -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 @@
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 b54f2f8..550c20d 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
@@ -103,23 +103,28 @@
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 @@
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 @@
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 @@
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);
}
}
}
@@ -193,7 +198,16 @@
}
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/main/java/org/glassfish/jersey/logging/ServerLoggingFilter.java b/core-common/src/main/java/org/glassfish/jersey/logging/ServerLoggingFilter.java
index a9c38de..8f7fc5f 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, 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
@@ -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 d1dd8e4..f12e2eb 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, 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
@@ -16,14 +16,27 @@
package org.glassfish.jersey.logging;
+import org.mockito.stubbing.Answer;
+
import jakarta.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 jakarta.ws.rs.core.MediaType.APPLICATION_OCTET_STREAM_TYPE;
import static jakarta.ws.rs.core.MediaType.TEXT_HTML_TYPE;
@@ -106,4 +119,67 @@
assertFalse(LoggingInterceptor.printEntity(HEADERS_ONLY, APPLICATION_OCTET_STREAM_TYPE));
}
+ //
+ // logInboundEntity
+ //
+
+ @Test
+ public void testLogInboundEntityMockedStream() throws Exception {
+ int maxEntitySize = 20;
+ LoggingInterceptor loggingInterceptor = new LoggingInterceptor(LoggingFeature.builder().maxEntitySize(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(LoggingFeature.builder().maxEntitySize(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 27602ae..530db3c 100644
--- a/core-common/src/test/resources/surefire.policy
+++ b/core-common/src/test/resources/surefire.policy
@@ -29,12 +29,15 @@
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/-" {
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 33293bb..8ca2039 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 @@
}
/**
- * 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 25015fd..a46fdad 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 @@
@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 @@
* 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 @@
* 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 @@
* 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 @@
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 @@
} 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 @@
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 @@
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 @@
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 f9beb52..9e9bdd7 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 @@
* <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 @@
* <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 @@
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/ContainerRequest.java b/core-server/src/main/java/org/glassfish/jersey/server/ContainerRequest.java
index 87e0564..a91521d 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
@@ -31,6 +31,7 @@
import java.util.function.Function;
import java.util.stream.Collectors;
+import jakarta.ws.rs.RuntimeType;
import jakarta.ws.rs.container.ContainerRequestContext;
import jakarta.ws.rs.container.ContainerRequestFilter;
import jakarta.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 @@
// 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 @@
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());
+ }
+ });
}
/**
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 7864041..87d16a5 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, 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
@@ -62,7 +62,11 @@
} 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/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 f85e751..ac01938 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 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/docs/src/main/docbook/appendix-properties.xml b/docs/src/main/docbook/appendix-properties.xml
index 7eb6347..8591dac 100644
--- a/docs/src/main/docbook/appendix-properties.xml
+++ b/docs/src/main/docbook/appendix-properties.xml
@@ -195,6 +195,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>
@@ -647,6 +658,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>
@@ -1016,6 +1038,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 c8b2cf9..2ee4675 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
@@ -429,14 +429,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>">
@@ -910,14 +913,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>">
@@ -1062,4 +1068,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/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 b79a196..2ad04c1 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 jakarta.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 @@
}
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 3e8f981..23ac90d 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 jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
+import jakarta.xml.bind.annotation.XmlElement;
@Path("/entity/")
public final class ServiceTest {
@@ -45,6 +46,7 @@
this.value = value;
}
+ @XmlElement(name = "jaxb")
@JsonGetter("name")
public final String getName() {
return name;
diff --git a/pom.xml b/pom.xml
index 2f27a94..9ba3d2b 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>
@@ -2036,7 +2042,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>
<commons-lang3.version>3.3.2</commons-lang3.version>
@@ -2060,7 +2066,7 @@
<hk2.jvnet.osgi.version>org.jvnet.hk2.*;version="[2.5,4)"</hk2.jvnet.osgi.version>
<hk2.config.version>6.0.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>
<javassist.version>3.25.0-GA</javassist.version>
<jboss.logging.version>3.3.0.Final</jboss.logging.version>
<jersey1.version>1.19.3</jersey1.version>
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 0000000..33acc33
--- /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 jakarta.validation.constraints.NotNull;
+import jakarta.ws.rs.DefaultValue;
+import jakarta.ws.rs.GET;
+import jakarta.ws.rs.HeaderParam;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.QueryParam;
+import jakarta.ws.rs.core.Application;
+import jakarta.ws.rs.core.Response;
+import jakarta.ws.rs.ext.ParamConverter;
+import jakarta.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;
+ }
+ };
+ }
+ }
+}
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 882b505..e24905f 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 @@
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 @@
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));
+ }
+
}
/**