diff --git a/NOTICE.md b/NOTICE.md index dac1f90716..bd12480dfd 100644 --- a/NOTICE.md +++ b/NOTICE.md @@ -1,4 +1,4 @@ -# Notice for Jersey +# Notice for Jersey This content is produced and maintained by the Eclipse Jersey project. * Project home: https://projects.eclipse.org/projects/ee4j.jersey @@ -57,25 +57,25 @@ Bootstrap v3.3.7 * Project: http://getbootstrap.com * Copyright: 2011-2016 Twitter, Inc -Google Guava Version 18.0 +Google Guava Version 33.3.0-jre * License: Apache License, 2.0 -* Copyright (C) 2009 The Guava Authors +* Copyright (C) 2009, 2024 The Guava Authors -jakarta.inject Version: 1 +jakarta.inject Version: 2.0.1 * License: Apache License, 2.0 -* Copyright (C) 2009 The JSR-330 Expert Group +* Copyright (C) 2009, 2021 The JSR-330 Expert Group Javassist Version 3.30.2-GA * License: Apache License, 2.0 * Project: http://www.javassist.org/ * Copyright (C) 1999- Shigeru Chiba. All Rights Reserved. -Jackson JAX-RS Providers Version 2.17.1 +Jackson JAX-RS Providers Version 2.17.2 * License: Apache License, 2.0 * Project: https://github.com/FasterXML/jackson-jaxrs-providers * Copyright: (c) 2009-2024 FasterXML, LLC. All rights reserved unless otherwise indicated. -jQuery v1.12.4 +jQuery v3.7.1 * License: jquery.org/license * Project: jquery.org * Copyright: (c) jQuery Foundation diff --git a/core-client/src/main/java/org/glassfish/jersey/client/ClientProperties.java b/core-client/src/main/java/org/glassfish/jersey/client/ClientProperties.java index 88a3d017d7..364bff088c 100644 --- a/core-client/src/main/java/org/glassfish/jersey/client/ClientProperties.java +++ b/core-client/src/main/java/org/glassfish/jersey/client/ClientProperties.java @@ -240,11 +240,34 @@ public final class ClientProperties { @PropertyAlias public static final String OUTBOUND_CONTENT_LENGTH_BUFFER = CommonProperties.OUTBOUND_CONTENT_LENGTH_BUFFER_CLIENT; + /** + * If {@code true} then disable configuration of Json Binding (JSR-367) + * feature on client. + *

+ * By default, Json Binding on client is automatically enabled if global + * property + * {@value org.glassfish.jersey.CommonProperties#JSON_BINDING_FEATURE_DISABLE} + * is not disabled. If set then the client property value overrides the + * global property value. + *

+ * The default value is {@code false}. + *

+ *

+ * The name of the configuration property is {@value}. + *

+ *

This constant is an alias for {@link CommonProperties#JSON_BINDING_FEATURE_DISABLE_CLIENT}.

+ * + * @see org.glassfish.jersey.CommonProperties#JSON_BINDING_FEATURE_DISABLE + * @since 2.45 + */ + @PropertyAlias + public static final String JSON_BINDING_FEATURE_DISABLE = CommonProperties.JSON_BINDING_FEATURE_DISABLE_CLIENT; + /** * If {@code true} then disable configuration of Json Processing (JSR-353) * feature on client. *

- * By default Json Processing on client is automatically enabled if global + * By default, Json Processing on client is automatically enabled if global * property * {@value org.glassfish.jersey.CommonProperties#JSON_PROCESSING_FEATURE_DISABLE} * is not disabled. If set then the client property value overrides the @@ -265,7 +288,7 @@ public final class ClientProperties { /** * If {@code true} then disable META-INF/services lookup on client. *

- * By default Jersey looks up SPI implementations described by {@code META-INF/services/*} files. + * By default, Jersey looks up SPI implementations described by {@code META-INF/services/*} files. * Then you can register appropriate provider classes by {@link jakarta.ws.rs.core.Application}. *

*

diff --git a/core-client/src/main/java/org/glassfish/jersey/client/HttpUrlConnectorProvider.java b/core-client/src/main/java/org/glassfish/jersey/client/HttpUrlConnectorProvider.java index 90d138d06e..306e336cef 100644 --- a/core-client/src/main/java/org/glassfish/jersey/client/HttpUrlConnectorProvider.java +++ b/core-client/src/main/java/org/glassfish/jersey/client/HttpUrlConnectorProvider.java @@ -21,6 +21,9 @@ import java.net.Proxy; import java.net.URL; import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; import java.util.logging.Logger; import jakarta.ws.rs.client.Client; @@ -295,9 +298,26 @@ default HttpURLConnection getConnection(URL url, Proxy proxy) throws IOException private static class DefaultConnectionFactory implements ConnectionFactory { + private final ConcurrentHashMap locks = new ConcurrentHashMap<>(); + @Override public HttpURLConnection getConnection(final URL url) throws IOException { - return (HttpURLConnection) url.openConnection(); + return connect(url, null); + } + + @Override + public HttpURLConnection getConnection(URL url, Proxy proxy) throws IOException { + return connect(url, proxy); + } + + private HttpURLConnection connect(URL url, Proxy proxy) throws IOException { + Lock lock = locks.computeIfAbsent(url, u -> new ReentrantLock()); + lock.lock(); + try { + return (proxy == null) ? (HttpURLConnection) url.openConnection() : (HttpURLConnection) url.openConnection(proxy); + } finally { + lock.unlock(); + } } } diff --git a/core-common/src/main/java/org/glassfish/jersey/ApplicationSupplier.java b/core-common/src/main/java/org/glassfish/jersey/ApplicationSupplier.java new file mode 100644 index 0000000000..6ef17b9718 --- /dev/null +++ b/core-common/src/main/java/org/glassfish/jersey/ApplicationSupplier.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * 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; + +import jakarta.ws.rs.core.Application; + +/** + * Implementation of this interface is capable of returning {@link Application}. + */ +public interface ApplicationSupplier { + /** + * Get Application. + * + * @return Application. + */ + Application getApplication(); + +} diff --git a/core-common/src/main/java/org/glassfish/jersey/CommonProperties.java b/core-common/src/main/java/org/glassfish/jersey/CommonProperties.java index ced63b3aca..308ff94ff6 100644 --- a/core-common/src/main/java/org/glassfish/jersey/CommonProperties.java +++ b/core-common/src/main/java/org/glassfish/jersey/CommonProperties.java @@ -71,7 +71,7 @@ public final class CommonProperties { /** * If {@code true} then disable feature auto discovery globally on client/server. *

- * By default auto discovery is automatically enabled. The value of this property may be overridden by the client/server + * By default, auto discovery is automatically enabled. The value of this property may be overridden by the client/server * variant of this property. *

* The default value is {@code false}. @@ -98,10 +98,55 @@ public final class CommonProperties { */ public static final String FEATURE_AUTO_DISCOVERY_DISABLE_SERVER = "jersey.config.server.disableAutoDiscovery"; + + /** + * If {@code true} then disable configuration of Json Binding (JSR-367) feature. + *

+ * By default, Json Binding is automatically enabled. The value of this property may be overridden by the client/server + * variant of this property. + *

+ * The default value is {@code false}. + *

+ *

+ * The name of the configuration property is {@value}. + *

+ * @since 2.45 + */ + public static final String JSON_BINDING_FEATURE_DISABLE = "jersey.config.disableJsonBinding"; + + /** + * Client-specific version of {@link CommonProperties#JSON_BINDING_FEATURE_DISABLE}. + * + * If present, it overrides the generic one for the client environment. + * @since 2.45 + */ + public static final String JSON_BINDING_FEATURE_DISABLE_CLIENT = "jersey.config.client.disableJsonBinding"; + + /** + * Server-specific version of {@link CommonProperties#JSON_BINDING_FEATURE_DISABLE}. + * + * If present, it overrides the generic one for the server environment. + * @since 2.45 + */ + public static final String JSON_BINDING_FEATURE_DISABLE_SERVER = "jersey.config.server.disableJsonBinding"; + + /** + * Disables configuration of Json Binding (JSR-367) feature for {@link jakarta.ws.rs.core.Application} subclasses whose + * package names are specified as a value. The value is comma-separated string defining prefixes of the application + * package names. + *

+ * By default, Json Binding is automatically enabled. + *

+ * The name of the configuration property is {@value}. + *

+ * @since 2.45 + */ + public static final String JSON_BINDING_FEATURE_DISABLE_APPLICATION = "jersey.config.application.disableJsonBinding"; + /** * If {@code true} then disable configuration of Json Processing (JSR-353) feature. *

- * By default Json Processing is automatically enabled. The value of this property may be overridden by the client/server + * By default, Json Processing is automatically enabled. The value of this property may be overridden by the client/server * variant of this property. *

* The default value is {@code false}. @@ -131,7 +176,7 @@ public final class CommonProperties { /** * If {@code true} then disable META-INF/services lookup globally on client/server. *

- * By default Jersey looks up SPI implementations described by META-INF/services/* files. + * By default, Jersey looks up SPI implementations described by META-INF/services/* files. * Then you can register appropriate provider classes by {@link jakarta.ws.rs.core.Application}. *

*

@@ -164,7 +209,7 @@ public final class CommonProperties { /** * If {@code true} then disable configuration of MOXy Json feature. *

- * By default MOXy Json is automatically enabled. The value of this property may be overridden by the client/server + * By default, MOXy Json is automatically enabled. The value of this property may be overridden by the client/server * variant of this property. *

* The default value is {@code false}. diff --git a/core-common/src/main/java/org/glassfish/jersey/internal/util/PropertiesHelper.java b/core-common/src/main/java/org/glassfish/jersey/internal/util/PropertiesHelper.java index 5500e54a76..97dee37a2c 100644 --- a/core-common/src/main/java/org/glassfish/jersey/internal/util/PropertiesHelper.java +++ b/core-common/src/main/java/org/glassfish/jersey/internal/util/PropertiesHelper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0, which is available at @@ -389,6 +389,27 @@ public static boolean isProperty(final Object value) { } } + /** + * Converts the property value to {@code boolean} and checks it is {@code true} or empty. + * Returns {@code true} if the value is {@code true} or empty but not {@code null}. + * + *

+ * The rationale behind this is that system property {@code -Dprop=true} is the same as {@code -Dprop}. + * The property {@code -Dprop=false} behaves as if the {@code -Dprop} is not set at all. + *

+ * + * @param value property value. + * @return {@code boolean} property value or {@code true} if the property value is not set or {@code false} if the property + * is otherwise not convertible. + */ + public static boolean isPropertyOrNotSet(final Object value) { + if (value instanceof Boolean) { + return Boolean.class.cast(value); + } else { + return value != null && ("".equals(value.toString()) || Boolean.parseBoolean(value.toString())); + } + } + /** * Faster replacement of {@code RuntimeType#name().toLowerCase(Locale.ROOT)} * @param runtimeType The runtime type to lower case diff --git a/core-common/src/main/java/org/glassfish/jersey/internal/util/collection/Views.java b/core-common/src/main/java/org/glassfish/jersey/internal/util/collection/Views.java index 32e2640e9e..4765056bbf 100644 --- a/core-common/src/main/java/org/glassfish/jersey/internal/util/collection/Views.java +++ b/core-common/src/main/java/org/glassfish/jersey/internal/util/collection/Views.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2019 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2024 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0, which is available at @@ -24,13 +24,12 @@ import java.util.List; import java.util.ListIterator; import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Collectors; -import static org.glassfish.jersey.internal.guava.Preconditions.checkNotNull; - /** * Collections utils, which provide transforming views for {@link List} and {@link Map}. * @@ -197,8 +196,8 @@ public int size() { * @return union view of given sets. */ public static Set setUnionView(final Set set1, final Set set2) { - checkNotNull(set1, "set1"); - checkNotNull(set2, "set2"); + Objects.requireNonNull(set1, "set1"); + Objects.requireNonNull(set2, "set2"); return new AbstractSet() { @Override @@ -220,18 +219,19 @@ private Set getUnion(Set set1, Set set2) { } /** - * Create a view of a difference of provided sets. + * Create a view of a difference of provided sets, i.e. the diff filters out from the first set the items included + * in the second set. *

* View is updated whenever any of the provided set changes. * * @param set1 first set. * @param set2 second set. * @param set item type. - * @return union view of given sets. + * @return view that is a difference of given sets. */ public static Set setDiffView(final Set set1, final Set set2) { - checkNotNull(set1, "set1"); - checkNotNull(set2, "set2"); + Objects.requireNonNull(set1, "set1"); + Objects.requireNonNull(set2, "set2"); return new AbstractSet() { @Override diff --git a/core-common/src/main/java/org/glassfish/jersey/io/package-info.java b/core-common/src/main/java/org/glassfish/jersey/io/package-info.java new file mode 100644 index 0000000000..f913ae650d --- /dev/null +++ b/core-common/src/main/java/org/glassfish/jersey/io/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * 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 + */ + +/** + * Common Jersey core io classes. + */ +package org.glassfish.jersey.io; diff --git a/core-common/src/main/java/org/glassfish/jersey/io/spi/FlushedCloseable.java b/core-common/src/main/java/org/glassfish/jersey/io/spi/FlushedCloseable.java new file mode 100644 index 0000000000..12aa7144d8 --- /dev/null +++ b/core-common/src/main/java/org/glassfish/jersey/io/spi/FlushedCloseable.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * 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.io.spi; + +import java.io.Closeable; +import java.io.Flushable; +import java.io.IOException; +import java.io.OutputStream; + +/** + * A marker interface that the stream provided to Jersey can implement, + * noting that the stream does not need to call {@link #flush()} prior to {@link #close()}. + * That way, {@link #flush()} method is not called twice. + * + *

+ * Usable by {@link javax.ws.rs.client.ClientRequestContext#setEntityStream(OutputStream)}. + * Usable by {@link javax.ws.rs.container.ContainerResponseContext#setEntityStream(OutputStream)}. + *

+ * + *

+ * This marker interface can be useful for the customer OutputStream to know the {@code flush} did not come from + * Jersey before close. By default, when the entity stream is to be closed by Jersey, {@code flush} is called first. + *

+ */ +public interface FlushedCloseable extends Flushable, Closeable { + /** + * Flushes this stream by writing any buffered output to the underlying stream. + * Then closes this stream and releases any system resources associated + * with it. If the stream is already closed then invoking this + * method has no effect. + * + *

As noted in {@link AutoCloseable#close()}, cases where the + * close may fail require careful attention. It is strongly advised + * to relinquish the underlying resources and to internally + * mark the {@code Closeable} as closed, prior to throwing + * the {@code IOException}. + * + * @throws IOException if an I/O error occurs + */ + public void close() throws IOException; +} diff --git a/core-common/src/main/java/org/glassfish/jersey/io/spi/package-info.java b/core-common/src/main/java/org/glassfish/jersey/io/spi/package-info.java new file mode 100644 index 0000000000..7a70945f25 --- /dev/null +++ b/core-common/src/main/java/org/glassfish/jersey/io/spi/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * 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 + */ + +/** + * Common Jersey core io SPI classes. + */ +package org.glassfish.jersey.io.spi; diff --git a/core-common/src/main/java/org/glassfish/jersey/message/internal/OutboundMessageContext.java b/core-common/src/main/java/org/glassfish/jersey/message/internal/OutboundMessageContext.java index c69f173f9a..b1b7745bbd 100644 --- a/core-common/src/main/java/org/glassfish/jersey/message/internal/OutboundMessageContext.java +++ b/core-common/src/main/java/org/glassfish/jersey/message/internal/OutboundMessageContext.java @@ -46,6 +46,7 @@ import org.glassfish.jersey.internal.util.collection.LazyValue; import org.glassfish.jersey.internal.util.collection.Value; import org.glassfish.jersey.internal.util.collection.Values; +import org.glassfish.jersey.io.spi.FlushedCloseable; /** * Base outbound message context implementation. @@ -561,11 +562,13 @@ public void close() { if (hasEntity()) { try { final OutputStream es = getEntityStream(); - es.flush(); + if (!FlushedCloseable.class.isInstance(es)) { + es.flush(); + } es.close(); } catch (IOException e) { // Happens when the client closed connection before receiving the full response. - // This is OK and not interesting in vast majority of the cases + // This is OK and not interesting in the vast majority of the cases // hence the log level set to FINE to make sure it does not flood the log unnecessarily // (especially for clients disconnecting from SSE listening, which is very common). Logger.getLogger(OutboundMessageContext.class.getName()).log(Level.FINE, e.getMessage(), e); diff --git a/core-common/src/test/java/org/glassfish/jersey/internal/util/PropertiesHelperTest.java b/core-common/src/test/java/org/glassfish/jersey/internal/util/PropertiesHelperTest.java index 67df36939c..237e749deb 100644 --- a/core-common/src/test/java/org/glassfish/jersey/internal/util/PropertiesHelperTest.java +++ b/core-common/src/test/java/org/glassfish/jersey/internal/util/PropertiesHelperTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2024 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0, which is available at @@ -199,4 +199,15 @@ public void testconvertValue() { } + @Test + public void isPropertyOrNotSetTest() { + assertEquals(false, PropertiesHelper.isPropertyOrNotSet((Boolean) null)); + assertEquals(true, PropertiesHelper.isPropertyOrNotSet(Boolean.TRUE)); + assertEquals(false, PropertiesHelper.isPropertyOrNotSet(Boolean.FALSE)); + assertEquals(false, PropertiesHelper.isPropertyOrNotSet((String) null)); + assertEquals(true, PropertiesHelper.isPropertyOrNotSet("")); + assertEquals(false, PropertiesHelper.isPropertyOrNotSet("treu")); // false for non-boolean values + assertEquals(true, PropertiesHelper.isPropertyOrNotSet("TRUE")); + assertEquals(false, PropertiesHelper.isPropertyOrNotSet("false")); + } } diff --git a/core-server/src/main/java/org/glassfish/jersey/server/ResourceConfig.java b/core-server/src/main/java/org/glassfish/jersey/server/ResourceConfig.java index ae39a6848f..6fc7a2a15b 100644 --- a/core-server/src/main/java/org/glassfish/jersey/server/ResourceConfig.java +++ b/core-server/src/main/java/org/glassfish/jersey/server/ResourceConfig.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0, which is available at @@ -39,6 +39,7 @@ import jakarta.ws.rs.core.Configuration; import jakarta.ws.rs.core.Feature; +import org.glassfish.jersey.ApplicationSupplier; import org.glassfish.jersey.internal.Errors; import org.glassfish.jersey.internal.config.ExternalPropertiesConfigurationFactory; import org.glassfish.jersey.internal.inject.Binder; @@ -70,7 +71,7 @@ * @author Michal Gajdos * @author Marek Potociar */ -public class ResourceConfig extends Application implements Configurable, ServerConfig { +public class ResourceConfig extends Application implements Configurable, ServerConfig, ApplicationSupplier { private static final Logger LOGGER = Logger.getLogger(ResourceConfig.class.getName()); diff --git a/core-server/src/main/java/org/glassfish/jersey/server/ServerProperties.java b/core-server/src/main/java/org/glassfish/jersey/server/ServerProperties.java index 5d8a3ad16d..3ef8565b8c 100644 --- a/core-server/src/main/java/org/glassfish/jersey/server/ServerProperties.java +++ b/core-server/src/main/java/org/glassfish/jersey/server/ServerProperties.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0, which is available at @@ -304,7 +304,7 @@ public final class ServerProperties { /** * If {@code true} then disable auto discovery on server. * - * By default auto discovery is automatically enabled if global property + * By default, auto discovery is automatically enabled if global property * {@value org.glassfish.jersey.CommonProperties#FEATURE_AUTO_DISCOVERY_DISABLE} is not disabled. If set then the server * property value overrides the global property value. *

@@ -344,10 +344,29 @@ public final class ServerProperties { @PropertyAlias public static final String OUTBOUND_CONTENT_LENGTH_BUFFER = CommonProperties.OUTBOUND_CONTENT_LENGTH_BUFFER_SERVER; + /** + * If {@code true} then disable configuration of Json Binding (JSR-367) feature on server. + * + * By default, Json Binding is automatically enabled if global property + * {@value org.glassfish.jersey.CommonProperties#JSON_BINDING_FEATURE_DISABLE} is not disabled. If set then the server + * property value overrides the global property value. + *

+ * The default value is {@code false}. + *

+ *

+ * The name of the configuration property is {@value}. + *

+ *

This constant is an alias for {@link CommonProperties#JSON_BINDING_FEATURE_DISABLE_SERVER}

+ * + * @see org.glassfish.jersey.CommonProperties#JSON_BINDING_FEATURE_DISABLE + */ + @PropertyAlias + public static final String JSON_BINDING_FEATURE_DISABLE = CommonProperties.JSON_BINDING_FEATURE_DISABLE_SERVER; + /** * If {@code true} then disable configuration of Json Processing (JSR-353) feature on server. * - * By default Json Processing is automatically enabled if global property + * By default, Json Processing is automatically enabled if global property * {@value org.glassfish.jersey.CommonProperties#JSON_PROCESSING_FEATURE_DISABLE} is not disabled. If set then the server * property value overrides the global property value. *

@@ -366,7 +385,7 @@ public final class ServerProperties { /** * If {@code true} then disable META-INF/services lookup on server. * - * By default Jersey looks up SPI implementations described by META-INF/services/* files. + * By default, Jersey looks up SPI implementations described by META-INF/services/* files. * Then you can register appropriate provider classes by {@link jakarta.ws.rs.core.Application}. *

* The default value is {@code false}. @@ -385,7 +404,7 @@ public final class ServerProperties { /** * If {@code true} then disable configuration of MOXy Json feature on server. * - * By default MOXy Json is automatically enabled if global property + * By default, MOXy Json is automatically enabled if global property * {@value org.glassfish.jersey.CommonProperties#MOXY_JSON_FEATURE_DISABLE} is not disabled. If set then the server * property value overrides the global property value. *

diff --git a/docs/src/main/docbook/appendix-properties.xml b/docs/src/main/docbook/appendix-properties.xml index 02cf239e2c..4294baeff4 100644 --- a/docs/src/main/docbook/appendix-properties.xml +++ b/docs/src/main/docbook/appendix-properties.xml @@ -71,6 +71,40 @@ + + &jersey.common.CommonProperties.JSON_BINDING_FEATURE_DISABLE; / + &jersey.common.CommonProperties.JSON_BINDING_FEATURE_DISABLE_CLIENT; / + &jersey.common.CommonProperties.JSON_BINDING_FEATURE_DISABLE_SERVER; + jersey.config.disableJsonBinding / + jersey.config.client.disableJsonBinding / + jersey.config.server.disableJsonBinding + + + Disables configuration of Json Binding (JSR-367) feature. Default value is false. + Can also be set as a system property. + + + Since 2.45. + + + + + &jersey.common.CommonProperties.JSON_BINDING_FEATURE_DISABLE_APPLICATION; + jersey.config.application.disableJsonBinding + + + Disables configuration of Json Binding (JSR-367) feature for jakarta.ws.rs.core.Application + subclasses whose package names are specified as a value. The value is comma-separated string + defining prefixes of the application package names. Can also be set as a system property. + + + By default, Json Binding is automatically enabled. + + + Since 2.45. + + + &jersey.common.CommonProperties.JSON_PROCESSING_FEATURE_DISABLE; / &jersey.common.CommonProperties.JSON_PROCESSING_FEATURE_DISABLE_CLIENT; / @@ -415,6 +449,15 @@ + + &jersey.server.ServerProperties.JSON_BINDING_FEATURE_DISABLE; + jersey.config.server.disableJsonBinding + + + Disables configuration of Json Processing (JSR-353) feature. Default value is false. + + + &jersey.server.ServerProperties.JSON_PROCESSING_FEATURE_DISABLE; jersey.config.server.disableJsonProcessing @@ -1105,6 +1148,15 @@ + + &jersey.client.ClientProperties.JSON_BINDING_FEATURE_DISABLE; + jersey.config.client.disableJsonBinding + + + Disables configuration of Json Binding (JSR-367) feature. Default value is false. + + + &jersey.client.ClientProperties.JSON_PROCESSING_FEATURE_DISABLE; jersey.config.client.disableJsonProcessing diff --git a/docs/src/main/docbook/jersey.ent b/docs/src/main/docbook/jersey.ent index 1893612e5c..5fe6f8a5b5 100644 --- a/docs/src/main/docbook/jersey.ent +++ b/docs/src/main/docbook/jersey.ent @@ -351,6 +351,7 @@ ClientProperties.DEFAULT_CHUNK_SIZE" > ClientProperties.FEATURE_AUTO_DISCOVERY_DISABLE" > ClientProperties.FOLLOW_REDIRECTS" > +ClientProperties.JSON_BINDING_FEATURE_DISABLE" > ClientProperties.JSON_PROCESSING_FEATURE_DISABLE" > ClientProperties.METAINF_SERVICES_LOOKUP_DISABLE" > ClientProperties.MOXY_JSON_FEATURE_DISABLE" > @@ -396,6 +397,10 @@ CommonProperties.FEATURE_AUTO_DISCOVERY_DISABLE" > CommonProperties.FEATURE_AUTO_DISCOVERY_DISABLE_CLIENT" > CommonProperties.FEATURE_AUTO_DISCOVERY_DISABLE_SERVER" > +CommonProperties.JSON_BINDING_FEATURE_DISABLE" > +CommonProperties.JSON_BINDING_FEATURE_DISABLE_CLIENT" > +CommonProperties.JSON_BINDING_FEATURE_DISABLE_SERVER" > +CommonProperties.JSON_BINDING_FEATURE_DISABLE_APPLICATION" > CommonProperties.JSON_PROCESSING_FEATURE_DISABLE" > CommonProperties.JSON_PROCESSING_FEATURE_DISABLE_CLIENT" > CommonProperties.JSON_PROCESSING_FEATURE_DISABLE_SERVER" > @@ -626,6 +631,7 @@ ServerProperties.BV_SEND_ERROR_IN_RESPONSE" > ServerProperties.FEATURE_AUTO_DISCOVERY_DISABLE" > ServerProperties.HTTP_METHOD_OVERRIDE" > +ServerProperties.JSON_BINDING_FEATURE_DISABLE" > ServerProperties.JSON_PROCESSING_FEATURE_DISABLE" > ServerProperties.LANGUAGE_MAPPINGS" > ServerProperties.MEDIA_TYPE_MAPPINGS" > diff --git a/examples/NOTICE.md b/examples/NOTICE.md index 4fa2d36777..6f522b3e89 100644 --- a/examples/NOTICE.md +++ b/examples/NOTICE.md @@ -1,4 +1,4 @@ -# Notice for Jersey +# Notice for Jersey This content is produced and maintained by the Eclipse Jersey project. * Project home: https://projects.eclipse.org/projects/ee4j.jersey @@ -39,8 +39,8 @@ aopalliance Version 1 Bean Validation API 3.0.2 * License: Apache License, 2.0 -* Project: http://beanvalidation.org/1.1/ -* Copyright: 2009, Red Hat, Inc. and/or its affiliates, and individual contributors +* Project: http://beanvalidation.org/3.0/ +* Copyright: 2009, 2020 Red Hat, Inc. and/or its affiliates, and individual contributors * by the @authors tag. Hibernate Validator CDI, 8.0.1.Final @@ -58,25 +58,25 @@ CDI API Version 3.0 * Project: http://www.seamframework.org/Weld * Copyright 2010, Red Hat, Inc., and individual contributors by the @authors tag. -Google Guava Version 18.0 +Google Guava Version 33.3.0-jre * License: Apache License, 2.0 -* Copyright (C) 2009 The Guava Authors +* Copyright (C) 2009, 2024 The Guava Authors -jakarta.inject Version: 1 +jakarta.inject Version: 2.0.1 * License: Apache License, 2.0 -* Copyright (C) 2009 The JSR-330 Expert Group +* Copyright (C) 2009, 2021 The JSR-330 Expert Group Javassist Version 3.30.2-GA * License: Apache License, 2.0 * Project: http://www.javassist.org/ * Copyright (C) 1999- Shigeru Chiba. All Rights Reserved. -Jackson JAX-RS Providers Version 2.17.1 +Jackson JAX-RS Providers Version 2.17.2 * License: Apache License, 2.0 * Project: https://github.com/FasterXML/jackson-jaxrs-providers * Copyright: (c) 2009-2023 FasterXML, LLC. All rights reserved unless otherwise indicated. -jQuery v1.12.4 +jQuery v3.7.1 * License: jquery.org/license * Project: jquery.org * Copyright: (c) jQuery Foundation diff --git a/examples/extended-wadl-webapp/README.MD b/examples/extended-wadl-webapp/README.MD index d7a59d12d0..6c4f676b6a 100644 --- a/examples/extended-wadl-webapp/README.MD +++ b/examples/extended-wadl-webapp/README.MD @@ -15,9 +15,6 @@ jersey. Contents -------- -The description of what's done here you'll find in the [jersey 1 -wiki](https://wikis.oracle.com/display/Jersey/HowToConfigureExtendedWADL). - The difference in configuration against jersey 1.x is in property configuring the custom WadlGeneratorConfig. Instead of property key 'com.sun.jersey.config.property.WadlGeneratorConfig' use the property @@ -48,6 +45,8 @@ into your existing GlassFish instance, you will need to follow instructions at [the module README file](../../README.html) in order to deploy the example. +NOTE: the example must be run with a JDK prior to JDK 13 otherwise javadoc plugin won't work properly. + Otherwise, you can run the example using embedded GlassFish as follows: You can run the example using Grizzly as follows: diff --git a/examples/extended-wadl-webapp/pom.xml b/examples/extended-wadl-webapp/pom.xml index 37d5044c65..6cc3283113 100644 --- a/examples/extended-wadl-webapp/pom.xml +++ b/examples/extended-wadl-webapp/pom.xml @@ -108,7 +108,7 @@ org.slf4j - slf4j-log4j12 + slf4j-reload4j ${slf4j.version} test @@ -150,7 +150,7 @@ org.codehaus.mojo jaxb2-maven-plugin - 2.5.0 + 3.2.0 xjc @@ -290,6 +290,57 @@ + + javadocAndTestsSkipJDK13 + + [13,) + + + + + org.apache.maven.plugins + maven-javadoc-plugin + + true + + + + org.apache.maven.plugins + maven-surefire-plugin + + true + + + + maven-antrun-plugin + + + generate-resources + + run + + + + **************************************************** + ****THIS EXAMPLE WORKS ONLY ON JDKs PRIOR to 13!**** + ********CURRENT JDK IS NOT SUPPORTED!*************** + **************************************************** + + + + + + + org.jvnet.jaxb2.maven2 + maven-jaxb2-plugin + 0.14.0 + + false + + + + + pre-release diff --git a/examples/osgi-http-service/functional-test/pom.xml b/examples/osgi-http-service/functional-test/pom.xml index 576fb1c599..6e74fc891a 100644 --- a/examples/osgi-http-service/functional-test/pom.xml +++ b/examples/osgi-http-service/functional-test/pom.xml @@ -144,7 +144,7 @@ org.slf4j - slf4j-log4j12 + slf4j-reload4j ${slf4j.version} test diff --git a/examples/servlet3-webapp/pom.xml b/examples/servlet3-webapp/pom.xml index 1a6968d968..96f742a18d 100644 --- a/examples/servlet3-webapp/pom.xml +++ b/examples/servlet3-webapp/pom.xml @@ -111,6 +111,15 @@ + + jdk8_tests + + 1.8 + + + ${junit5.jdk8.version} + + pre-release diff --git a/ext/cdi/jersey-cdi1x/src/main/java/org/glassfish/jersey/ext/cdi1x/internal/CdiComponentProvider.java b/ext/cdi/jersey-cdi1x/src/main/java/org/glassfish/jersey/ext/cdi1x/internal/CdiComponentProvider.java index e41d4c904d..a47aced693 100644 --- a/ext/cdi/jersey-cdi1x/src/main/java/org/glassfish/jersey/ext/cdi1x/internal/CdiComponentProvider.java +++ b/ext/cdi/jersey-cdi1x/src/main/java/org/glassfish/jersey/ext/cdi1x/internal/CdiComponentProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2024 Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2018, 2022 Payara Foundation and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the @@ -45,7 +45,6 @@ import jakarta.inject.Singleton; import jakarta.ws.rs.core.Application; - import jakarta.annotation.ManagedBean; import jakarta.enterprise.context.Dependent; import jakarta.enterprise.context.RequestScoped; @@ -143,6 +142,8 @@ public Boolean apply(final Class clazz) { private volatile Map, Set> methodsToSkip = new HashMap<>(); private volatile Map, Set> fieldsToSkip = new HashMap<>(); + private boolean initialized = false; + public CdiComponentProvider() { customHk2TypesProvider = CdiUtil.lookupService(Hk2CustomBoundTypesProvider.class); injectionManagerStore = CdiUtil.createHk2InjectionManagerStore(); @@ -154,7 +155,7 @@ public void initialize(final InjectionManager injectionManager) { this.injectionManager = injectionManager; this.beanManager = CdiUtil.getBeanManager(); - if (beanManager != null) { + if (beanManager != null && !injectionManager.getClass().getSimpleName().equals("NonInjectionManager")) { // Try to get CdiComponentProvider created by CDI. final CdiComponentProvider extension = beanManager.getExtension(CdiComponentProvider.class); @@ -167,18 +168,19 @@ public void initialize(final InjectionManager injectionManager) { bindHk2ClassAnalyzer(); LOGGER.config(LocalizationMessages.CDI_PROVIDER_INITIALIZED()); + initialized = true; } } } @Override public boolean bind(final Class clazz, final Set> providerContracts) { - return bind(clazz, providerContracts, ContractProvider.NO_PRIORITY); + return initialized && bind(clazz, providerContracts, ContractProvider.NO_PRIORITY); } @Override public boolean bind(Class component, ContractProvider contractProvider) { - return contractProvider != null + return initialized && contractProvider != null ? bind(component, contractProvider.getContracts(), contractProvider.getPriority(component)) : bind(component, Collections.EMPTY_SET); } @@ -628,11 +630,8 @@ private void bindHk2ClassAnalyzer() { ClassAnalyzer defaultClassAnalyzer = injectionManager.getInstance(ClassAnalyzer.class, ClassAnalyzer.DEFAULT_IMPLEMENTATION_NAME); - int skippedElements = methodsToSkip.size() + fieldsToSkip.size(); - - ClassAnalyzer customizedClassAnalyzer = skippedElements > 0 - ? new InjecteeSkippingAnalyzer(defaultClassAnalyzer, methodsToSkip, fieldsToSkip, beanManager) - : defaultClassAnalyzer; + ClassAnalyzer customizedClassAnalyzer = + new InjecteeSkippingAnalyzer(defaultClassAnalyzer, methodsToSkip, fieldsToSkip, beanManager); Binder binder = new AbstractBinder() { @Override diff --git a/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/bean/BeanHelper.java b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/bean/BeanHelper.java index b653b549cf..a1c5032e60 100644 --- a/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/bean/BeanHelper.java +++ b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/bean/BeanHelper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0, which is available at @@ -129,13 +129,7 @@ public static void registerSupplier(RuntimeType runtimeType, InitializableSu * CDI does not provide sufficient support for ThreadScoped Supplier */ if (binding.getScope() == PerThread.class) { - BeanManagerImpl manager; - if (beanManager instanceof BeanManagerProxy) { - manager = ((BeanManagerProxy) beanManager).unwrap(); - } else { - manager = (BeanManagerImpl) beanManager; - } - abd.addBean(new InitializableSupplierThreadScopeBean(runtimeType, binding, manager)); + abd.addBean(new InitializableSupplierThreadScopeBean(runtimeType, binding, beanManagerImpl(beanManager))); } else { abd.addBean(new InitializableSupplierInstanceBean<>(runtimeType, binding)); abd.addBean(new InitializableSupplierInstanceBeanBridge<>(runtimeType, binding)); @@ -164,12 +158,18 @@ public static BindingBeanPair registerSupplier(RuntimeType runtimeType, Supp InjectionTarget> jit = getJerseyInjectionTarget(supplierClass, injectionTarget, supplierBean, resolvers); supplierBean.setInjectionTarget(jit); - final SupplierBeanBridge supplierBeanBridge = new SupplierBeanBridge(runtimeType, binding, beanManager); - - abd.addBean(supplierBean); - abd.addBean(supplierBeanBridge); - - return new BindingBeanPair(binding, supplierBean, supplierBeanBridge); + /* + * CDI does not provide sufficient support for ThreadScoped Supplier + */ + if (binding.getScope() == PerThread.class) { + abd.addBean(new SupplierThreadScopeClassBean(runtimeType, binding, supplierBean, beanManagerImpl(beanManager))); + return null; + } else { + final SupplierBeanBridge supplierBeanBridge = new SupplierBeanBridge(runtimeType, binding, beanManager); + abd.addBean(supplierBean); + abd.addBean(supplierBeanBridge); + return new BindingBeanPair(binding, supplierBean, supplierBeanBridge); + } } /** @@ -258,6 +258,14 @@ private static ConstructorInjectionPoint createConstructorInjectionPoint( return null; } + private static BeanManagerImpl beanManagerImpl(BeanManager beanManager) { + if (beanManager instanceof BeanManagerProxy) { + return ((BeanManagerProxy) beanManager).unwrap(); + } else { + return (BeanManagerImpl) beanManager; + } + } + private static InjectionTarget getJerseyInjectionTarget(Class clazz, InjectionTarget injectionTarget, Bean bean, Collection resolvers) { BasicInjectionTarget it = (BasicInjectionTarget) injectionTarget; diff --git a/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/bean/InitializableSupplierThreadScopeBean.java b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/bean/InitializableSupplierThreadScopeBean.java index c5f211e885..3415b46c13 100644 --- a/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/bean/InitializableSupplierThreadScopeBean.java +++ b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/bean/InitializableSupplierThreadScopeBean.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0, which is available at @@ -111,31 +111,4 @@ private T createClientProxy(BeanInstance beanInstance, String contextId) { ProxyFactory factory = new ProxyFactory<>(contextId, getBeanClass(), getTypes(), this); return factory.create(beanInstance); } - - private static class ThreadScopeBeanInstance extends ContextBeanInstance { - - private final WeakHashMap instances = new WeakHashMap<>(); - - private final Supplier supplier; - - /** - * Creates a new invocation handler with supplier which provides a current injected value in proper scope. - * - * @param supplier provider of the value. - */ - private ThreadScopeBeanInstance(Supplier supplier, Bean bean, String contextId) { - super(bean, new StringBeanIdentifier(((PassivationCapable) bean).getId()), contextId); - this.supplier = supplier; - } - - @Override - public Object invoke(Object obj, Method method, Object... arguments) throws Throwable { - Object instance = instances.computeIfAbsent(Thread.currentThread(), thread -> supplier.get()); - return super.invoke(instance, method, arguments); - } - - public void dispose() { - this.instances.clear(); - } - } } diff --git a/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/bean/SupplierThreadScopeClassBean.java b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/bean/SupplierThreadScopeClassBean.java new file mode 100644 index 0000000000..fe3e8b4ebd --- /dev/null +++ b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/bean/SupplierThreadScopeClassBean.java @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * 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.inject.weld.internal.bean; + +import org.glassfish.jersey.internal.inject.SupplierClassBinding; +import org.glassfish.jersey.internal.inject.SupplierInstanceBinding; +import org.glassfish.jersey.internal.util.collection.LazyValue; +import org.glassfish.jersey.internal.util.collection.Value; +import org.glassfish.jersey.internal.util.collection.Values; +import org.jboss.weld.bean.proxy.BeanInstance; +import org.jboss.weld.bean.proxy.ProxyFactory; +import org.jboss.weld.manager.BeanManagerImpl; + +import jakarta.enterprise.context.Dependent; +import jakarta.enterprise.context.spi.CreationalContext; +import jakarta.ws.rs.RuntimeType; +import java.lang.annotation.Annotation; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Supplier; + + +/** + * Creates an implementation of {@link jakarta.enterprise.inject.spi.Bean} interface using Jersey's {@link SupplierInstanceBinding}. + * Binding provides the information about the bean also called {@link jakarta.enterprise.inject.spi.BeanAttributes} information. + * The {@code Bean} does not use {@link org.glassfish.jersey.inject.weld.internal.injector.JerseyInjectionTarget} because serves already + * created proxy, therefore the create operation just return provided instance without any other contextual operation + * (produce, inject, destroy). + *

+ * This bean is special and is used only for service registered as a {@link org.glassfish.jersey.internal.inject.PerThread} and + * works through the proxy which serves the correct instance per the given thread. + *

+ * Register example: + *

+ * AbstractBinder {
+ *     @Override
+ *     protected void configure() {
+ *         bindFactory(MyFactoryInjectionSupplier.class)
+ *              .to(MyBean.class)
+ *              .in(PerThread.class);
+ *     }
+ * }
+ * 
+ * Inject example: + *
+ * @Path("/")
+ * public class MyResource {
+ *   @Inject
+ *   private MyBean myBean;
+ * }
+ * 
+ */ +class SupplierThreadScopeClassBean extends JerseyBean { + private final LazyValue> beanInstance; + private final SupplierClassBinding binding; + private final LazyValue proxy; + private final AtomicReference creationalContextAtomicReference = new AtomicReference<>(); + + SupplierThreadScopeClassBean(RuntimeType runtimeType, + SupplierClassBinding binding, + SupplierClassBean supplierClassBean, + BeanManagerImpl beanManager) { + super(runtimeType, binding); + this.binding = binding; + this.beanInstance = Values.lazy((Value>) () -> { + Supplier supplierInstance = supplierClassBean.create(creationalContextAtomicReference.get()); + ThreadScopeBeanInstance scopeBeanInstance = + new ThreadScopeBeanInstance(supplierInstance, this, beanManager.getContextId()); + return scopeBeanInstance; + }); + this.proxy = Values.lazy((Value) () -> createClientProxy(beanInstance.get(), beanManager.getContextId())); + } + + @Override + public Class getScope() { + return Dependent.class; + } + + @Override + public Object create(CreationalContext ctx) { + creationalContextAtomicReference.set(ctx); + return proxy.get(); + } + + @Override + public void destroy(Object instance, CreationalContext creationalContext) { + if (beanInstance.isInitialized()) { + this.beanInstance.get().dispose(); + } + } + + @Override + public Class getBeanClass() { + return (Class) this.binding.getContracts().iterator().next(); + } + + private T createClientProxy(BeanInstance beanInstance, String contextId) { + ProxyFactory factory = new ProxyFactory<>(contextId, getBeanClass(), getTypes(), this); + return factory.create(beanInstance); + } +} diff --git a/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/bean/ThreadScopeBeanInstance.java b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/bean/ThreadScopeBeanInstance.java new file mode 100644 index 0000000000..73ac6514aa --- /dev/null +++ b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/bean/ThreadScopeBeanInstance.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2021, 2024 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * 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.inject.weld.internal.bean; + +import org.jboss.weld.bean.StringBeanIdentifier; +import org.jboss.weld.bean.proxy.ContextBeanInstance; + +import jakarta.enterprise.inject.spi.Bean; +import jakarta.enterprise.inject.spi.PassivationCapable; +import java.lang.reflect.Method; +import java.util.WeakHashMap; +import java.util.function.Supplier; + +/** + * {@link org.glassfish.jersey.internal.inject.PerThread} scope bean instance used from + * {@link InitializableSupplierThreadScopeBean} and {@link SupplierThreadScopeClassBean}. + * + * @param Typed of the bean supplied by a {@code Supplier}. + */ +class ThreadScopeBeanInstance extends ContextBeanInstance { + + private final WeakHashMap instances = new WeakHashMap<>(); + + private final Supplier supplier; + + /** + * Creates a new invocation handler with supplier which provides a current injected value in proper scope. + * + * @param supplier provider of the value. + */ + ThreadScopeBeanInstance(Supplier supplier, Bean bean, String contextId) { + super(bean, new StringBeanIdentifier(((PassivationCapable) bean).getId()), contextId); + this.supplier = supplier; + } + + @Override + public Object invoke(Object obj, Method method, Object... arguments) throws Throwable { + Object instance = instances.computeIfAbsent(Thread.currentThread(), thread -> supplier.get()); + return super.invoke(instance, method, arguments); + } + + public void dispose() { + this.instances.clear(); + } +} diff --git a/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/managed/BinderRegisterExtension.java b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/managed/BinderRegisterExtension.java index 60d48e4a0e..8917bb09ba 100644 --- a/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/managed/BinderRegisterExtension.java +++ b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/managed/BinderRegisterExtension.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0, which is available at @@ -347,8 +347,10 @@ private void registerBeans(RuntimeType runtimeType, CachingBinder binder, AfterB } BindingBeanPair pair = BeanHelper.registerSupplier( runtimeType, (SupplierClassBinding) binding, abd, injectionResolvers, beanManager); - for (Type contract : ((SupplierClassBinding) binding).getContracts()) { - supplierClassBindings.add(contract, pair); + if (pair != null) { + for (Type contract : ((SupplierClassBinding) binding).getContracts()) { + supplierClassBindings.add(contract, pair); + } } } else if (InitializableInstanceBinding.class.isAssignableFrom(binding.getClass())) { if (RuntimeType.SERVER == runtimeType diff --git a/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/managed/CzechGreeting.java b/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/managed/CzechGreeting.java index 68b57d950a..14bd26853d 100644 --- a/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/managed/CzechGreeting.java +++ b/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/managed/CzechGreeting.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0, which is available at @@ -26,9 +26,11 @@ public class CzechGreeting implements Greeting, Printable { static final String GREETING = "Ahoj"; + private String greeting = GREETING + "#" + Thread.currentThread().getName(); + @Override public String getGreeting() { - return GREETING + "#" + Thread.currentThread().getName(); + return greeting; } @Override diff --git a/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/managed/TestPreinitialization.java b/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/managed/TestPreinitialization.java index b7806c15cc..97d4a491c9 100644 --- a/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/managed/TestPreinitialization.java +++ b/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/managed/TestPreinitialization.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0, which is available at @@ -97,6 +97,13 @@ public void register(RuntimeType runtimeType, AbstractBinder binder) { binder.bindFactory(new ThreadScopeTest.SupplierGreeting2(ThreadScopeTest.EnglishGreeting2.GREETING)) .to(ThreadScopeTest.EnglishGreeting2.class) .in(PerThread.class); + + //testSupplierClassBindingThreadScopedInSingletonScope + binder.bindAsContract(ThreadScopeTest.SingletonObject3.class) + .in(Singleton.class); + binder.bindFactory(ThreadScopeTest.SupplierGreeting3.class) + .to(ThreadScopeTest.Greeting3.class) + .in(PerThread.class); } //ClientInstanceInjectionTest diff --git a/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/managed/ThreadScopeTest.java b/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/managed/ThreadScopeTest.java index 144c333968..7c959fefec 100644 --- a/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/managed/ThreadScopeTest.java +++ b/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/managed/ThreadScopeTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0, which is available at @@ -18,6 +18,7 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; import java.util.function.Supplier; import jakarta.enterprise.context.RequestScoped; @@ -181,7 +182,7 @@ public void testThreadScopedInRequestTwoTypes() { } @Test - public void testThreadScopedInSingletonScope() { + public void testThreadScopedInSingletonScope() throws InterruptedException { // InjectionManager injectionManager = BindingTestHelper.createInjectionManager(); // BindingTestHelper.bind(injectionManager, binder -> { // binder.bindAsContract(SingletonObject.class) @@ -202,6 +203,52 @@ public void testThreadScopedInSingletonScope() { assertNotNull(greeting2); assertEquals(greeting1, greeting2); + + final AtomicReference greetingAtomicReference = new AtomicReference<>(); + Runnable runnable = () -> + greetingAtomicReference.set(injectionManager.getInstance(SingletonObject.class).getGreeting().getGreeting()); + + Thread newThread = new Thread(runnable); + newThread.start(); + newThread.join(); + + assertEquals(greeting1.getGreeting(), greeting2.getGreeting()); + assertNotEquals(greeting1.getGreeting(), greetingAtomicReference.get()); + } + + @Test + public void testSupplierClassBindingThreadScopedInSingletonScope() throws InterruptedException { +// InjectionManager injectionManager = BindingTestHelper.createInjectionManager(); +// BindingTestHelper.bind(injectionManager, binder -> { +// binder.bindAsContract(SingletonObject.class) +// .in(Singleton.class); +// +// binder.bindFactory(SupplierGreeting.class) +// .to(Greeting.class) +// .in(PerThread.class); +// }); + + SingletonObject3 instance1 = injectionManager.getInstance(SingletonObject3.class); + Greeting3 greeting1 = instance1.getGreeting(); + assertNotNull(greeting1); + + // Precisely the same object + SingletonObject3 instance2 = injectionManager.getInstance(SingletonObject3.class); + Greeting3 greeting2 = instance2.getGreeting(); + assertNotNull(greeting2); + + assertEquals(greeting1, greeting2); + + final AtomicReference greetingAtomicReference = new AtomicReference<>(); + Runnable runnable = () -> + greetingAtomicReference.set(injectionManager.getInstance(SingletonObject3.class).getGreeting().getGreeting()); + + Thread newThread = new Thread(runnable); + newThread.start(); + newThread.join(); + + assertEquals(greeting1.getGreeting(), greeting2.getGreeting()); + assertNotEquals(greeting1.getGreeting(), greetingAtomicReference.get()); } @RequestScoped @@ -226,6 +273,17 @@ public CzechGreeting getGreeting() { } } + @Singleton + public static class SingletonObject3 { + + @Inject + Greeting3 greeting; + + public Greeting3 getGreeting() { + return greeting; + } + } + @Singleton public static class SingletonObject { @@ -259,6 +317,14 @@ public EnglishGreeting2 getGreeting() { } } + @Vetoed + static class SupplierGreeting3 implements Supplier { + @Override + public Greeting3 get() { + return new CzechGreeting3(); + } + } + @Vetoed static class SupplierGreeting2 implements Supplier { @@ -290,14 +356,34 @@ public Greeting2 get() { } } + @Vetoed + static class CzechGreeting3 implements Greeting3 { + + static final String GREETING = "Ahoj"; + + private String greeting = GREETING + "#" + Thread.currentThread().getName(); + + @Override + public String getGreeting() { + return greeting; + } + + @Override + public String toString() { + return "CzechGreeting"; + } + } + @Vetoed static class CzechGreeting2 implements Greeting2 { static final String GREETING = "Ahoj"; + private String greeting = GREETING + "#" + Thread.currentThread().getName(); + @Override public String getGreeting() { - return GREETING + "#" + Thread.currentThread().getName(); + return greeting; } @Override @@ -374,9 +460,11 @@ static class CzechGreeting implements Greeting { static final String GREETING = "Ahoj"; + private String greeting = GREETING + "#" + Thread.currentThread().getName(); + @Override public String getGreeting() { - return GREETING + "#" + Thread.currentThread().getName(); + return greeting; } @Override @@ -385,6 +473,11 @@ public String toString() { } } + @FunctionalInterface + static interface Greeting3 { + String getGreeting(); + } + @FunctionalInterface static interface Greeting2 { String getGreeting(); diff --git a/inject/cdi2-se/src/main/java/org/glassfish/jersey/inject/cdi/se/bean/BeanHelper.java b/inject/cdi2-se/src/main/java/org/glassfish/jersey/inject/cdi/se/bean/BeanHelper.java index 584193f5bd..053dbe8f92 100644 --- a/inject/cdi2-se/src/main/java/org/glassfish/jersey/inject/cdi/se/bean/BeanHelper.java +++ b/inject/cdi2-se/src/main/java/org/glassfish/jersey/inject/cdi/se/bean/BeanHelper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0, which is available at @@ -116,18 +116,11 @@ public static void registerBean(ClassBinding binding, AfterBeanDiscovery * @param type of the instance which is registered. */ public static void registerSupplier(SupplierInstanceBinding binding, AfterBeanDiscovery abd, BeanManager beanManager) { - BeanManagerImpl manager; - if (beanManager instanceof BeanManagerProxy) { - manager = ((BeanManagerProxy) beanManager).unwrap(); - } else { - manager = (BeanManagerImpl) beanManager; - } - /* * CDI does not provide sufficient support for ThreadScoped Supplier */ if (binding.getScope() == PerThread.class) { - abd.addBean(new SupplierThreadScopeBean(binding, manager)); + abd.addBean(new SupplierThreadScopeBean(binding, beanManagerImpl(beanManager))); } else { abd.addBean(new SupplierInstanceBean<>(binding)); abd.addBean(new SupplierInstanceBeanBridge<>(binding)); @@ -156,8 +149,23 @@ public static void registerSupplier(SupplierClassBinding binding, AfterBe InjectionTarget> jit = getJerseyInjectionTarget(supplierClass, injectionTarget, supplierBean, resolvers); supplierBean.setInjectionTarget(jit); - abd.addBean(supplierBean); - abd.addBean(new SupplierBeanBridge(binding, beanManager)); + /* + * CDI does not provide sufficient support for ThreadScoped Supplier + */ + if (binding.getScope() == PerThread.class) { + abd.addBean(new SupplierThreadScopeClassBean(binding, supplierBean, beanManagerImpl(beanManager))); + } else { + abd.addBean(supplierBean); + abd.addBean(new SupplierBeanBridge(binding, beanManager)); + } + } + + private static BeanManagerImpl beanManagerImpl(BeanManager beanManager) { + if (beanManager instanceof BeanManagerProxy) { + return ((BeanManagerProxy) beanManager).unwrap(); + } else { + return (BeanManagerImpl) beanManager; + } } private static InjectionTarget getJerseyInjectionTarget(Class clazz, InjectionTarget injectionTarget, diff --git a/inject/cdi2-se/src/main/java/org/glassfish/jersey/inject/cdi/se/bean/SupplierThreadScopeBean.java b/inject/cdi2-se/src/main/java/org/glassfish/jersey/inject/cdi/se/bean/SupplierThreadScopeBean.java index a0c0d340b4..b95ae0a539 100644 --- a/inject/cdi2-se/src/main/java/org/glassfish/jersey/inject/cdi/se/bean/SupplierThreadScopeBean.java +++ b/inject/cdi2-se/src/main/java/org/glassfish/jersey/inject/cdi/se/bean/SupplierThreadScopeBean.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0, which is available at @@ -17,20 +17,13 @@ package org.glassfish.jersey.inject.cdi.se.bean; import java.lang.annotation.Annotation; -import java.lang.reflect.Method; -import java.util.WeakHashMap; -import java.util.function.Supplier; import jakarta.enterprise.context.Dependent; import jakarta.enterprise.context.spi.CreationalContext; -import jakarta.enterprise.inject.spi.Bean; -import jakarta.enterprise.inject.spi.PassivationCapable; import org.glassfish.jersey.internal.inject.SupplierInstanceBinding; -import org.jboss.weld.bean.StringBeanIdentifier; import org.jboss.weld.bean.proxy.BeanInstance; -import org.jboss.weld.bean.proxy.ContextBeanInstance; import org.jboss.weld.bean.proxy.ProxyFactory; import org.jboss.weld.manager.BeanManagerImpl; @@ -107,31 +100,4 @@ private T createClientProxy(BeanInstance beanInstance, String contextId) { ProxyFactory factory = new ProxyFactory<>(contextId, getBeanClass(), getTypes(), this); return factory.create(beanInstance); } - - private static class ThreadScopeBeanInstance extends ContextBeanInstance { - - private final WeakHashMap instances = new WeakHashMap<>(); - - private final Supplier supplier; - - /** - * Creates a new invocation handler with supplier which provides a current injected value in proper scope. - * - * @param supplier provider of the value. - */ - private ThreadScopeBeanInstance(Supplier supplier, Bean bean, String contextId) { - super(bean, new StringBeanIdentifier(((PassivationCapable) bean).getId()), contextId); - this.supplier = supplier; - } - - @Override - public Object invoke(Object obj, Method method, Object... arguments) throws Throwable { - Object instance = instances.computeIfAbsent(Thread.currentThread(), thread -> supplier.get()); - return super.invoke(instance, method, arguments); - } - - public void dispose() { - this.instances.clear(); - } - } } diff --git a/inject/cdi2-se/src/main/java/org/glassfish/jersey/inject/cdi/se/bean/SupplierThreadScopeClassBean.java b/inject/cdi2-se/src/main/java/org/glassfish/jersey/inject/cdi/se/bean/SupplierThreadScopeClassBean.java new file mode 100644 index 0000000000..698bfb034d --- /dev/null +++ b/inject/cdi2-se/src/main/java/org/glassfish/jersey/inject/cdi/se/bean/SupplierThreadScopeClassBean.java @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * 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.inject.cdi.se.bean; + +import java.lang.annotation.Annotation; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Supplier; + +import jakarta.enterprise.context.Dependent; +import jakarta.enterprise.context.spi.CreationalContext; + +import org.glassfish.jersey.internal.inject.SupplierClassBinding; +import org.glassfish.jersey.internal.inject.SupplierInstanceBinding; +import org.glassfish.jersey.internal.util.collection.LazyValue; +import org.glassfish.jersey.internal.util.collection.Value; +import org.glassfish.jersey.internal.util.collection.Values; +import org.jboss.weld.bean.proxy.BeanInstance; +import org.jboss.weld.bean.proxy.ProxyFactory; +import org.jboss.weld.manager.BeanManagerImpl; + + +/** + * Creates an implementation of {@link jakarta.enterprise.inject.spi.Bean} interface using Jersey's {@link SupplierInstanceBinding}. + * Binding provides the information about the bean also called {@link jakarta.enterprise.inject.spi.BeanAttributes} information. + * The {@code Bean} does not use {@link org.glassfish.jersey.inject.cdi.se.injector.JerseyInjectionTarget} because serves already + * created proxy, therefore the create operation just return provided instance without any other contextual operation + * (produce, inject, destroy). + *

+ * This bean is special and is used only for service registered as a {@link org.glassfish.jersey.internal.inject.PerThread} and + * works through the proxy which serves the correct instance per the given thread. + *

+ * Register example: + *

+ * AbstractBinder {
+ *     @Override
+ *     protected void configure() {
+ *         bindFactory(MyFactoryInjectionSupplier.class)
+ *              .to(MyBean.class)
+ *              .in(PerThread.class);
+ *     }
+ * }
+ * 
+ * Inject example: + *
+ * @Path("/")
+ * public class MyResource {
+ *   @Inject
+ *   private MyBean myBean;
+ * }
+ * 
+ */ +class SupplierThreadScopeClassBean extends JerseyBean { + private final LazyValue> beanInstance; + private final SupplierClassBinding binding; + private final LazyValue proxy; + private final AtomicReference creationalContextAtomicReference = new AtomicReference<>(); + + SupplierThreadScopeClassBean(SupplierClassBinding binding, SupplierClassBean supplierClassBean, BeanManagerImpl beanManager) { + super(binding); + this.binding = binding; + this.beanInstance = Values.lazy((Value>) () -> { + Supplier supplierInstance = supplierClassBean.create(creationalContextAtomicReference.get()); + ThreadScopeBeanInstance scopeBeanInstance = + new ThreadScopeBeanInstance(supplierInstance, this, beanManager.getContextId()); + return scopeBeanInstance; + }); + this.proxy = Values.lazy((Value) () -> createClientProxy(beanInstance.get(), beanManager.getContextId())); + } + + @Override + public Class getScope() { + return Dependent.class; + } + + @Override + public Object create(CreationalContext ctx) { + creationalContextAtomicReference.set(ctx); + return proxy.get(); + } + + @Override + public void destroy(Object instance, CreationalContext creationalContext) { + if (beanInstance.isInitialized()) { + this.beanInstance.get().dispose(); + } + } + + @Override + public Class getBeanClass() { + return (Class) this.binding.getContracts().iterator().next(); + } + + private T createClientProxy(BeanInstance beanInstance, String contextId) { + ProxyFactory factory = new ProxyFactory<>(contextId, getBeanClass(), getTypes(), this); + return factory.create(beanInstance); + } +} diff --git a/inject/cdi2-se/src/main/java/org/glassfish/jersey/inject/cdi/se/bean/ThreadScopeBeanInstance.java b/inject/cdi2-se/src/main/java/org/glassfish/jersey/inject/cdi/se/bean/ThreadScopeBeanInstance.java new file mode 100644 index 0000000000..a2009609f2 --- /dev/null +++ b/inject/cdi2-se/src/main/java/org/glassfish/jersey/inject/cdi/se/bean/ThreadScopeBeanInstance.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2017, 2024 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * 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.inject.cdi.se.bean; + +import org.jboss.weld.bean.StringBeanIdentifier; +import org.jboss.weld.bean.proxy.ContextBeanInstance; + +import java.lang.reflect.Method; +import java.util.WeakHashMap; +import java.util.function.Supplier; + +import jakarta.enterprise.inject.spi.Bean; +import jakarta.enterprise.inject.spi.PassivationCapable; + +/** + * {@link org.glassfish.jersey.internal.inject.PerThread} scope bean instance used from + * {@link SupplierThreadScopeBean} and {@link SupplierThreadScopeClassBean}. + * + * @param Typed of the bean supplied by a {@code Supplier}. + */ +class ThreadScopeBeanInstance extends ContextBeanInstance { + + private final WeakHashMap instances = new WeakHashMap<>(); + + private final Supplier supplier; + + /** + * Creates a new invocation handler with supplier which provides a current injected value in proper scope. + * + * @param supplier provider of the value. + */ + ThreadScopeBeanInstance(Supplier supplier, Bean bean, String contextId) { + super(bean, new StringBeanIdentifier(((PassivationCapable) bean).getId()), contextId); + this.supplier = supplier; + } + + @Override + public Object invoke(Object obj, Method method, Object... arguments) throws Throwable { + Object instance = instances.computeIfAbsent(Thread.currentThread(), thread -> supplier.get()); + return super.invoke(instance, method, arguments); + } + + public void dispose() { + this.instances.clear(); + } +} diff --git a/inject/cdi2-se/src/test/java/org/glassfish/jersey/inject/cdi/se/CzechGreeting.java b/inject/cdi2-se/src/test/java/org/glassfish/jersey/inject/cdi/se/CzechGreeting.java index fd4ae86d99..3f4f9245a6 100644 --- a/inject/cdi2-se/src/test/java/org/glassfish/jersey/inject/cdi/se/CzechGreeting.java +++ b/inject/cdi2-se/src/test/java/org/glassfish/jersey/inject/cdi/se/CzechGreeting.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0, which is available at @@ -26,9 +26,11 @@ public class CzechGreeting implements Greeting, Printable { static final String GREETING = "Ahoj"; + private String greeting = GREETING + "#" + Thread.currentThread().getName(); + @Override public String getGreeting() { - return GREETING + "#" + Thread.currentThread().getName(); + return greeting; } @Override diff --git a/inject/cdi2-se/src/test/java/org/glassfish/jersey/inject/cdi/se/ThreadScopeTest.java b/inject/cdi2-se/src/test/java/org/glassfish/jersey/inject/cdi/se/ThreadScopeTest.java index cf377c196c..1fe627a8ba 100644 --- a/inject/cdi2-se/src/test/java/org/glassfish/jersey/inject/cdi/se/ThreadScopeTest.java +++ b/inject/cdi2-se/src/test/java/org/glassfish/jersey/inject/cdi/se/ThreadScopeTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0, which is available at @@ -17,6 +17,7 @@ package org.glassfish.jersey.inject.cdi.se; import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicReference; import jakarta.enterprise.context.RequestScoped; import jakarta.inject.Inject; @@ -167,7 +168,7 @@ public void testThreadScopedInRequestTwoTypes() { } @Test - public void testThreadScopedInSingletonScope() { + public void testThreadScopedInSingletonScope() throws InterruptedException { InjectionManager injectionManager = BindingTestHelper.createInjectionManager(); BindingTestHelper.bind(injectionManager, binder -> { binder.bindAsContract(SingletonObject.class) @@ -188,6 +189,52 @@ public void testThreadScopedInSingletonScope() { assertNotNull(greeting2); assertEquals(greeting1, greeting2); + + final AtomicReference greetingAtomicReference = new AtomicReference<>(); + Runnable runnable = () -> + greetingAtomicReference.set(injectionManager.getInstance(SingletonObject.class).getGreeting().getGreeting()); + + Thread newThread = new Thread(runnable); + newThread.start(); + newThread.join(); + + assertEquals(greeting1.getGreeting(), greeting2.getGreeting()); + assertNotEquals(greeting1.getGreeting(), greetingAtomicReference.get()); + } + + @Test + public void testSupplierClassBindingThreadScopedInSingletonScope() throws InterruptedException { + InjectionManager injectionManager = BindingTestHelper.createInjectionManager(); + BindingTestHelper.bind(injectionManager, binder -> { + binder.bindAsContract(SingletonObject.class) + .in(Singleton.class); + + binder.bindFactory(SupplierGreeting.class) + .to(Greeting.class) + .in(PerThread.class); + }); + + SingletonObject instance1 = injectionManager.getInstance(SingletonObject.class); + Greeting greeting1 = instance1.getGreeting(); + assertNotNull(greeting1); + + // Precisely the same object + SingletonObject instance2 = injectionManager.getInstance(SingletonObject.class); + Greeting greeting2 = instance2.getGreeting(); + assertNotNull(greeting2); + + assertEquals(greeting1, greeting2); + + final AtomicReference greetingAtomicReference = new AtomicReference<>(); + Runnable runnable = () -> + greetingAtomicReference.set(injectionManager.getInstance(SingletonObject.class).getGreeting().getGreeting()); + + Thread newThread = new Thread(runnable); + newThread.start(); + newThread.join(); + + assertEquals(greeting1.getGreeting(), greeting2.getGreeting()); + assertNotEquals(greeting1.getGreeting(), greetingAtomicReference.get()); } @RequestScoped diff --git a/media/json-binding/src/main/java/org/glassfish/jersey/jsonb/JsonBindingFeature.java b/media/json-binding/src/main/java/org/glassfish/jersey/jsonb/JsonBindingFeature.java index b80ac9e4df..a41afb0956 100644 --- a/media/json-binding/src/main/java/org/glassfish/jersey/jsonb/JsonBindingFeature.java +++ b/media/json-binding/src/main/java/org/glassfish/jersey/jsonb/JsonBindingFeature.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0, which is available at @@ -16,16 +16,25 @@ package org.glassfish.jersey.jsonb; +import jakarta.ws.rs.RuntimeType; +import jakarta.ws.rs.core.Application; import jakarta.ws.rs.core.Configuration; import jakarta.ws.rs.core.Feature; import jakarta.ws.rs.core.FeatureContext; +import org.glassfish.jersey.ApplicationSupplier; import org.glassfish.jersey.CommonProperties; import org.glassfish.jersey.internal.InternalProperties; +import org.glassfish.jersey.internal.inject.InjectionManagerSupplier; import org.glassfish.jersey.internal.util.PropertiesHelper; import org.glassfish.jersey.jsonb.internal.JsonBindingAutoDiscoverable; import org.glassfish.jersey.jsonb.internal.JsonBindingProvider; +import java.security.AccessController; +import java.util.HashSet; +import java.util.Set; +import java.util.logging.Logger; + /** * Feature used to register JSON-B providers. *

@@ -50,12 +59,85 @@ */ public class JsonBindingFeature implements Feature { + private static final Logger LOGGER = Logger.getLogger(JsonBindingFeature.class.getName()); private static final String JSON_FEATURE = JsonBindingFeature.class.getSimpleName(); @Override public boolean configure(final FeatureContext context) { final Configuration config = context.getConfiguration(); + // ---- Allow to disable for compatibility with Pre JAX-RS 2.1 Jersey. + + /* Either system properties */ + final String bindingDisabledBySystemProperty = AccessController.doPrivileged( + PropertiesHelper.getSystemProperty(CommonProperties.JSON_BINDING_FEATURE_DISABLE)); + + final String bindingDisabledBySystemPropertyClient = AccessController.doPrivileged( + PropertiesHelper.getSystemProperty(CommonProperties.JSON_BINDING_FEATURE_DISABLE_CLIENT)); + + final String bindingDisabledBySystemPropertyServer = AccessController.doPrivileged( + PropertiesHelper.getSystemProperty(CommonProperties.JSON_BINDING_FEATURE_DISABLE_SERVER)); + + final RuntimeType runtimeType = config.getRuntimeType(); + + boolean bindingDisabledBySystem = PropertiesHelper.isPropertyOrNotSet(bindingDisabledBySystemProperty) + || (runtimeType == RuntimeType.CLIENT + && PropertiesHelper.isPropertyOrNotSet(bindingDisabledBySystemPropertyClient)) + || (runtimeType == RuntimeType.SERVER + && PropertiesHelper.isPropertyOrNotSet(bindingDisabledBySystemPropertyServer)); + + /* Or config property */ + final Boolean bindingDisabled = CommonProperties.getValue(config.getProperties(), runtimeType, + CommonProperties.JSON_BINDING_FEATURE_DISABLE, Boolean.class); + + /* Config property takes precedence */ + if ((bindingDisabledBySystem && !Boolean.FALSE.equals(bindingDisabled)) || Boolean.TRUE.equals(bindingDisabled)) { + return false; + } + + final Set disabledPackageNames = new HashSet<>(); + + /* Only a certain package names */ + final String bindingDisabledPackageBySystemProperty = RuntimeType.SERVER == runtimeType + ? AccessController.doPrivileged(PropertiesHelper.getSystemProperty( + CommonProperties.JSON_BINDING_FEATURE_DISABLE_APPLICATION)) + : null; + + final String bindingDisabledPackage = RuntimeType.SERVER == runtimeType + ? CommonProperties.getValue(config.getProperties(), runtimeType, + CommonProperties.JSON_BINDING_FEATURE_DISABLE_APPLICATION, String.class) + : null; + + separatePackageNames(disabledPackageNames, bindingDisabledPackageBySystemProperty); + separatePackageNames(disabledPackageNames, bindingDisabledPackage); + + if (!disabledPackageNames.isEmpty() && !Boolean.FALSE.equals(bindingDisabled)) { + try { + Application app = null; + if (InjectionManagerSupplier.class.isInstance(context)) { + app = ((InjectionManagerSupplier) context).getInjectionManager().getInstance(Application.class); + if (app != null) { + while (ApplicationSupplier.class.isInstance(app) && ((ApplicationSupplier) app).getApplication() != app) { + app = ((ApplicationSupplier) app).getApplication(); + } + for (String disabledPackageName : disabledPackageNames) { + if (app.getClass().getName().startsWith(disabledPackageName)) { + return false; + } + } + } + } + if (app == null) { + LOGGER.warning(LocalizationMessages.ERROR_JSONB_DETECTING_APPLICATION( + LocalizationMessages.ERROR_JSONB_APPLICATION_NOT_FOUND())); + } + } catch (Throwable throwable) { + LOGGER.warning(LocalizationMessages.ERROR_JSONB_DETECTING_APPLICATION(throwable.getMessage())); + } + } + + // ---- End of disabling for compatibility with Pre JAX-RS 2.1 Jersey. + final String jsonFeature = CommonProperties.getValue( config.getProperties(), config.getRuntimeType(), @@ -74,4 +156,12 @@ public boolean configure(final FeatureContext context) { return true; } + + private static void separatePackageNames(Set set, String packages) { + if (packages != null) { + for (String packageName : packages.split(",")) { + set.add(packageName.trim()); + } + } + } } diff --git a/media/json-binding/src/main/resources/org/glassfish/jersey/jsonb/localization.properties b/media/json-binding/src/main/resources/org/glassfish/jersey/jsonb/localization.properties index 4eee493a70..371e641b3d 100644 --- a/media/json-binding/src/main/resources/org/glassfish/jersey/jsonb/localization.properties +++ b/media/json-binding/src/main/resources/org/glassfish/jersey/jsonb/localization.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2017, 2019 Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2017, 2024 Oracle and/or its affiliates. All rights reserved. # # This program and the accompanying materials are made available under the # terms of the Eclipse Public License v. 2.0, which is available at @@ -14,6 +14,8 @@ # SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 # +error.jsonb.application.not.found=Application not found. +error.jsonb.detecting.application=JSON-B could not detect the application name: {0}. error.jsonb.serialization=Error writing JSON-B serialized object. error.jsonb.deserialization=Error deserializing object from entity stream. error.jsonb.emptystream=JSON-B cannot parse empty input stream. diff --git a/media/json-binding/src/test/java/org/glassfish/jersey/jsonb/internal/JsonbDisabledTest.java b/media/json-binding/src/test/java/org/glassfish/jersey/jsonb/internal/JsonbDisabledTest.java new file mode 100644 index 0000000000..7dc8a3f6a6 --- /dev/null +++ b/media/json-binding/src/test/java/org/glassfish/jersey/jsonb/internal/JsonbDisabledTest.java @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * 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.jsonb.internal; + +import org.glassfish.jersey.CommonProperties; +import org.glassfish.jersey.internal.inject.AbstractBinder; +import org.glassfish.jersey.internal.inject.InjectionManager; +import org.glassfish.jersey.internal.inject.InjectionManagerSupplier; +import org.glassfish.jersey.internal.inject.Injections; +import org.glassfish.jersey.jsonb.JsonBindingFeature; +import org.glassfish.jersey.model.internal.CommonConfig; +import org.glassfish.jersey.model.internal.ComponentBag; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import jakarta.ws.rs.RuntimeType; +import jakarta.ws.rs.core.Application; +import jakarta.ws.rs.core.FeatureContext; +import java.lang.reflect.Proxy; +import java.util.concurrent.atomic.AtomicReference; + +public class JsonbDisabledTest { + @Test + public void testDisabled() { + AtomicReference configReference = new AtomicReference<>(); + FeatureContext featureContext1 = featureContextForConfig(configReference); + + CommonConfig config1 = new CommonConfig(RuntimeType.SERVER, ComponentBag.INCLUDE_ALL); + configReference.set(config1); + Assertions.assertTrue(new JsonBindingFeature().configure(featureContext1)); + + CommonConfig config2 = new CommonConfig(RuntimeType.SERVER, ComponentBag.INCLUDE_ALL); + config2.property(CommonProperties.JSON_BINDING_FEATURE_DISABLE, true); + configReference.set(config2); + Assertions.assertFalse(new JsonBindingFeature().configure(featureContext1)); + } + + @Test + public void testDisabledBySystemProperty() { + AtomicReference configReference = new AtomicReference<>(); + FeatureContext featureContext1 = featureContextForConfig(configReference); + + CommonConfig config1 = new CommonConfig(RuntimeType.SERVER, ComponentBag.INCLUDE_ALL); + configReference.set(config1); + Assertions.assertTrue(new JsonBindingFeature().configure(featureContext1)); + + CommonConfig config2 = new CommonConfig(RuntimeType.SERVER, ComponentBag.INCLUDE_ALL); + System.setProperty(CommonProperties.JSON_BINDING_FEATURE_DISABLE_SERVER, "true"); + configReference.set(config2); + Assertions.assertFalse(new JsonBindingFeature().configure(featureContext1)); + System.clearProperty(CommonProperties.JSON_BINDING_FEATURE_DISABLE_SERVER); + } + + @Test + public void testDisabledBySystemPropertyOverridenByConfigProperty() { + AtomicReference configReference = new AtomicReference<>(); + FeatureContext featureContext1 = featureContextForConfig(configReference); + + CommonConfig config1 = new CommonConfig(RuntimeType.SERVER, ComponentBag.INCLUDE_ALL); + configReference.set(config1); + Assertions.assertTrue(new JsonBindingFeature().configure(featureContext1)); + + CommonConfig config2 = new CommonConfig(RuntimeType.SERVER, ComponentBag.INCLUDE_ALL); + System.setProperty(CommonProperties.JSON_BINDING_FEATURE_DISABLE, "true"); + config2.property(CommonProperties.JSON_BINDING_FEATURE_DISABLE, false); + configReference.set(config2); + Assertions.assertTrue(new JsonBindingFeature().configure(featureContext1)); + System.clearProperty(CommonProperties.JSON_BINDING_FEATURE_DISABLE); + } + + @Test + public void testDisabledByPropertyApplicationPackage() { + Application application = new Application() { + }; + InjectionManager injectionManager = Injections.createInjectionManager(); + injectionManager.register(new AbstractBinder() { + @Override + protected void configure() { + bind(application).to(Application.class); + } + }); + AtomicReference injectionManagerReference = new AtomicReference<>(injectionManager); + AtomicReference configReference = new AtomicReference<>(); + FeatureContext featureContext1 = featureContextForConfig(configReference, injectionManagerReference); + + CommonConfig config1 = new CommonConfig(RuntimeType.SERVER, ComponentBag.INCLUDE_ALL); + configReference.set(config1); + Assertions.assertTrue(new JsonBindingFeature().configure(featureContext1)); + + System.setProperty(CommonProperties.JSON_BINDING_FEATURE_DISABLE_APPLICATION, + "some.does.not.matter, org.glassfish.jersey.jsonb.internal"); + CommonConfig config2 = new CommonConfig(RuntimeType.SERVER, ComponentBag.INCLUDE_ALL); + configReference.set(config2); + Assertions.assertFalse(new JsonBindingFeature().configure(featureContext1)); + System.clearProperty(CommonProperties.JSON_BINDING_FEATURE_DISABLE_APPLICATION); + } + + @Test + public void disableOnClientOnlyTest() { + AtomicReference configReference = new AtomicReference<>(); + FeatureContext featureContext1 = featureContextForConfig(configReference); + + CommonConfig config1 = new CommonConfig(RuntimeType.CLIENT, ComponentBag.INCLUDE_ALL); + configReference.set(config1); + Assertions.assertTrue(new JsonBindingFeature().configure(featureContext1)); + + config1.property(CommonProperties.JSON_BINDING_FEATURE_DISABLE_SERVER, true); + Assertions.assertTrue(new JsonBindingFeature().configure(featureContext1)); + + config1.property(CommonProperties.JSON_BINDING_FEATURE_DISABLE_CLIENT, true); + Assertions.assertFalse(new JsonBindingFeature().configure(featureContext1)); + + CommonConfig config2 = new CommonConfig(RuntimeType.CLIENT, ComponentBag.INCLUDE_ALL); + System.setProperty(CommonProperties.JSON_BINDING_FEATURE_DISABLE_SERVER, "true"); + configReference.set(config2); + Assertions.assertTrue(new JsonBindingFeature().configure(featureContext1)); + + System.setProperty(CommonProperties.JSON_BINDING_FEATURE_DISABLE_CLIENT, "true"); + Assertions.assertFalse(new JsonBindingFeature().configure(featureContext1)); + + System.clearProperty(CommonProperties.JSON_BINDING_FEATURE_DISABLE_SERVER); + System.clearProperty(CommonProperties.JSON_BINDING_FEATURE_DISABLE_CLIENT); + } + + @Test + public void testDisabledBySystemPropertyApplicationPackage() { + Application application = new Application() { + }; + InjectionManager injectionManager = Injections.createInjectionManager(); + injectionManager.register(new AbstractBinder() { + @Override + protected void configure() { + bind(application).to(Application.class); + } + }); + AtomicReference injectionManagerReference = new AtomicReference<>(injectionManager); + AtomicReference configReference = new AtomicReference<>(); + FeatureContext featureContext1 = featureContextForConfig(configReference, injectionManagerReference); + + System.setProperty(CommonProperties.JSON_BINDING_FEATURE_DISABLE_APPLICATION, + "some.does.not.matter, org.glassfish.jersey.jsonb.internal"); + + CommonConfig config1 = new CommonConfig(RuntimeType.SERVER, ComponentBag.INCLUDE_ALL); + configReference.set(config1); + Assertions.assertFalse(new JsonBindingFeature().configure(featureContext1)); + + CommonConfig config2 = new CommonConfig(RuntimeType.SERVER, ComponentBag.INCLUDE_ALL); + configReference.set(config2); + Assertions.assertFalse(new JsonBindingFeature().configure(featureContext1)); + System.clearProperty(CommonProperties.JSON_BINDING_FEATURE_DISABLE_APPLICATION); + } + + @Test + public void testDisabledBySystemPropertyApplicationPackageEnabledByProperty() { + Application application = new Application() { + }; + InjectionManager injectionManager = Injections.createInjectionManager(); + injectionManager.register(new AbstractBinder() { + @Override + protected void configure() { + bind(application).to(Application.class); + } + }); + AtomicReference injectionManagerReference = new AtomicReference<>(injectionManager); + AtomicReference configReference = new AtomicReference<>(); + FeatureContext featureContext1 = featureContextForConfig(configReference, injectionManagerReference); + + CommonConfig config1 = new CommonConfig(RuntimeType.SERVER, ComponentBag.INCLUDE_ALL); + configReference.set(config1); + Assertions.assertTrue(new JsonBindingFeature().configure(featureContext1)); + + System.setProperty(CommonProperties.JSON_BINDING_FEATURE_DISABLE_APPLICATION, + "some.does.not.matter, org.glassfish.jersey.jsonb.internal"); + + CommonConfig config2 = new CommonConfig(RuntimeType.SERVER, ComponentBag.INCLUDE_ALL); + config2.property(CommonProperties.JSON_BINDING_FEATURE_DISABLE, Boolean.FALSE); + configReference.set(config2); + Assertions.assertTrue(new JsonBindingFeature().configure(featureContext1)); + System.clearProperty(CommonProperties.JSON_BINDING_FEATURE_DISABLE_APPLICATION); + } + + private static FeatureContext featureContextForConfig(AtomicReference configReference) { + return featureContextForConfig(configReference, new AtomicReference<>()); + } + private static FeatureContext featureContextForConfig(AtomicReference configReference, + AtomicReference injectionManager) { + return (FeatureContext) Proxy.newProxyInstance( + JsonbDisabledTest.class.getClassLoader(), + new Class[] {FeatureContext.class, InjectionManagerSupplier.class}, (proxy, method, args) -> { + switch (method.getName()) { + case "getConfiguration": + return configReference.get(); + case "getInjectionManager": + return injectionManager.get(); + } + return null; + }); + } +} diff --git a/media/json-gson/pom.xml b/media/json-gson/pom.xml index e856c38d12..2a3b5dbf2c 100644 --- a/media/json-gson/pom.xml +++ b/media/json-gson/pom.xml @@ -71,6 +71,12 @@ com.google.code.gson gson + + + com.google.errorprone + error_prone_annotations + + org.junit.jupiter 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 d7b9f9c096..a209c27c9d 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 @@ -59,10 +59,6 @@ public DefaultJacksonJaxbJsonProvider(@Context Providers providers, @Context Con //do not register JaxbAnnotationModule because it brakes default annotations processing private static final String[] EXCLUDE_MODULE_NAMES = {"JaxbAnnotationModule", "JakartaXmlBindAnnotationModule"}; - public DefaultJacksonJaxbJsonProvider() { - super(new JacksonMapperConfigurator(null, DEFAULT_ANNOTATIONS)); - } - public DefaultJacksonJaxbJsonProvider(Providers providers, Configuration config, Annotations... annotationsToUse) { super(new JacksonMapperConfigurator(null, annotationsToUse)); this.commonConfig = config; @@ -147,4 +143,4 @@ private void updateFactoryConstraints(JsonFactory jsonFactory) { ); } } -} \ No newline at end of file +} diff --git a/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/jackson/jaxrs/json/PackageVersion.java b/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/jackson/jaxrs/json/PackageVersion.java index 5d328da992..56b1bf6480 100644 --- a/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/jackson/jaxrs/json/PackageVersion.java +++ b/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/jackson/jaxrs/json/PackageVersion.java @@ -11,7 +11,7 @@ */ public final class PackageVersion implements Versioned { public final static Version VERSION = VersionUtil.parseVersion( - "2.17.1", "com.fasterxml.jackson.jaxrs", "jackson-jaxrs-json-provider"); + "2.17.2", "com.fasterxml.jackson.jaxrs", "jackson-jaxrs-json-provider"); @Override public Version version() { diff --git a/media/json-jackson/src/main/resources/META-INF/NOTICE.markdown b/media/json-jackson/src/main/resources/META-INF/NOTICE.markdown index 4edecfc595..9440229038 100644 --- a/media/json-jackson/src/main/resources/META-INF/NOTICE.markdown +++ b/media/json-jackson/src/main/resources/META-INF/NOTICE.markdown @@ -31,7 +31,7 @@ The project maintains the following source code repositories: ## Third-party Content -Jackson JAX-RS Providers version 2.17.1 +Jackson JAX-RS Providers version 2.17.2 * License: Apache License, 2.0 * Project: https://github.com/FasterXML/jackson-jaxrs-providers * Copyright: (c) 2009-2023 FasterXML, LLC. All rights reserved unless otherwise indicated. diff --git a/pom.xml b/pom.xml index cdb20097cf..eb00a8c4ae 100644 --- a/pom.xml +++ b/pom.xml @@ -153,14 +153,14 @@ http://www.eclipse.org/legal/epl-2.0 repo Except for 3rd content and examples. - See also https://github.com/eclipse-ee4j/jersey/blob/master/NOTICE.md + See also https://github.com/eclipse-ee4j/jersey/blob/master/NOTICE.md GPL2 w/ CPE https://www.gnu.org/software/classpath/license.html repo Except for 3rd content and examples. - See also https://github.com/eclipse-ee4j/jersey/blob/master/NOTICE.md + See also https://github.com/eclipse-ee4j/jersey/blob/master/NOTICE.md EDL 1.0 @@ -179,9 +179,9 @@ http://www.apache.org/licenses/LICENSE-2.0.html repo Google Guava @ org.glassfish.jersey.internal.guava, - Dropwizard Monitoring inspired classes @ org.glassfish.jersey.server.internal.monitoring.core, - Hibernate Validation classes @ org.glassfish.jersey.server.validation.internal.hibernate, and - Jackson JAX-RS Providers @ org.glassfish.jersey.jackson.internal.jackson.jaxrs + Dropwizard Monitoring inspired classes @ org.glassfish.jersey.server.internal.monitoring.core, + Hibernate Validation classes @ org.glassfish.jersey.server.validation.internal.hibernate, and + Jackson JAX-RS Providers @ org.glassfish.jersey.jackson.internal.jackson.jaxrs Public Domain @@ -206,7 +206,7 @@ http://www.opensource.org/licenses/mit-license.php repo AngularJS, Bootstrap v3.3.7, - jQuery Barcode plugin 0.3, KineticJS v4.7.1 + jQuery Barcode plugin 0.3, KineticJS v4.7.1 W3C license @@ -902,7 +902,7 @@ - + true @@ -929,7 +929,7 @@ false - !tests.excluded + !tests.excluded @@ -1025,10 +1025,10 @@ maven-enforcer-plugin - enforce-property - - enforce - + enforce-property + + enforce + @@ -1650,7 +1650,7 @@ org.simpleframework simple-http ${simple.version} - + org.simpleframework @@ -2023,9 +2023,9 @@ - com.google.code.gson - gson - ${gson.version} + com.google.code.gson + gson + ${gson.version} @@ -2059,8 +2059,8 @@ UTF-8 UTF-8 - - + + false @@ -2073,13 +2073,13 @@ 3.1.0 1.10.14 3.7.1 - 3.3.2 - 3.4.1 - 3.2.0 - 3.5.0 + 3.4.0 + 3.5.0 + 3.4.1 + 3.6.0 3.2.0 - 3.3.1 - 10.16.0 + 3.4.0 + 10.17.0 3.13.0 3.9.0 - 2.8.0 - 3.6.1 + 2.8.1 + 3.7.1 3.1.2 3.3.0 - 3.2.5 + 3.3.1 5.1.9 3.0.5 5.1 3.1.2 4.2.0 - 3.4.1 - 3.6.3 - 3.3.2 + 3.4.2 + 3.8.0 + 3.4.0 1.2.4 - 3.5.0 + 3.6.2 3.3.1 - 3.5.3 + 3.6.0 3.3.1 - 3.2.5 + 3.3.1 3.4.0 2.11.0 1.1.0 @@ -2121,25 +2121,25 @@ 9.7 - 1.9.22 - + 1.9.22.1 + 1.70 2.16.1 1.16.1 - - 1.3.1 + + 1.3.3 1.7.0 1.6.4 2.8.4 7.0.5 1.7 - 2.3.32 - 2.0.26 - 4.0.21 - 2.10.1 + 2.3.33 + 2.0.29 + 4.0.23 + 2.11.0 - + 0.27.0 3.0.2 @@ -2156,12 +2156,12 @@ 1.4.14 3.7.1 - 33.1.0-jre - 2.2 + 33.3.0-jre + 3.0 2.10.0 4.5.14 5.3.1 - 2.17.1 + 2.17.2 3.30.2-GA 1.3.7 3.3.2.Final @@ -2169,13 +2169,13 @@ 1.37 1.49 4.13.2 - 5.10.2 - 1.10.2 + 5.11.0 + 1.11.0 1.10.0 4.0.3 4.11.0 - 0.9.12 - 4.1.109.Final + 0.9.14 + 4.1.112.Final 0.33.0 6.0.0 1.10.0 @@ -2193,8 +2193,8 @@ 6.0.1 2.0.13 6.0.18 - 7.9.0 - 6.9.13.6 + 7.10.2 + 6.14.3 3.1.2.RELEASE 5.1.1.Final @@ -2205,7 +2205,7 @@ 2.12.2 - 20.3.14 + 20.3.15 7.0.6 @@ -2240,15 +2240,15 @@ 3.1 3.1.0 org.eclipse.jetty.*;version="[11,15)" - 12.0.7 - 9.4.54.v20240208 - 11.0.20 + 12.0.14 + 9.4.55.v20240627 + 11.0.24 12.0.8 3.0.1 1.1.5 1.1.5 - 4.0.2 - 3.0.3 + 4.0.4 + 3.0.4 1.3.2 diff --git a/tests/e2e-core-common/src/test/java/org/glassfish/jersey/tests/e2e/common/message/internal/OutboundMessageContextTest.java b/tests/e2e-core-common/src/test/java/org/glassfish/jersey/tests/e2e/common/message/internal/OutboundMessageContextTest.java index bd6e3c531a..817170c43b 100644 --- a/tests/e2e-core-common/src/test/java/org/glassfish/jersey/tests/e2e/common/message/internal/OutboundMessageContextTest.java +++ b/tests/e2e-core-common/src/test/java/org/glassfish/jersey/tests/e2e/common/message/internal/OutboundMessageContextTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2023 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0, which is available at @@ -16,6 +16,9 @@ package org.glassfish.jersey.tests.e2e.common.message.internal; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; import java.net.URI; import java.net.URISyntaxException; import java.text.ParseException; @@ -33,10 +36,13 @@ import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.ext.RuntimeDelegate; +import org.glassfish.jersey.io.spi.FlushedCloseable; import org.glassfish.jersey.message.internal.CookieProvider; import org.glassfish.jersey.message.internal.OutboundMessageContext; import org.glassfish.jersey.tests.e2e.common.TestRuntimeDelegate; +import org.hamcrest.MatcherAssert; +import org.hamcrest.Matchers; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import static org.hamcrest.Matchers.contains; @@ -271,4 +277,38 @@ public void testCopyConstructor() { newCtx.setMediaType(MediaType.APPLICATION_XML_TYPE); // new value Assertions.assertEquals(MediaType.APPLICATION_XML_TYPE, newCtx.getMediaType()); } + + @Test + public void OutboundMessageContextFlushTest() throws IOException { + FlushCountOutputStream os = new FlushCountOutputStream(); + OutboundMessageContext ctx = new OutboundMessageContext((Configuration) null); + ctx.setEntity("Anything"); + ctx.setEntityStream(os); + os.flush(); + ctx.close(); + MatcherAssert.assertThat(os.flushedCnt, Matchers.is(2)); + + os = new FlushedClosableOutputStream(); + ctx = new OutboundMessageContext((Configuration) null); + ctx.setEntity("Anything2"); + ctx.setEntityStream(os); + os.flush(); + ctx.close(); + MatcherAssert.assertThat(os.flushedCnt, Matchers.is(1)); + } + + private static class FlushCountOutputStream extends ByteArrayOutputStream { + private int flushedCnt = 0; + + @Override + public void flush() throws IOException { + flushedCnt++; + super.flush(); + } + } + + private static class FlushedClosableOutputStream extends FlushCountOutputStream implements FlushedCloseable { + + } } + diff --git a/tests/integration/cdi-integration/cdi-skipping-analyzer/pom.xml b/tests/integration/cdi-integration/cdi-skipping-analyzer/pom.xml new file mode 100644 index 0000000000..15c75183d4 --- /dev/null +++ b/tests/integration/cdi-integration/cdi-skipping-analyzer/pom.xml @@ -0,0 +1,71 @@ + + + + + + cdi-integration-project + org.glassfish.jersey.tests.integration.cdi + 3.1.99-SNAPSHOT + + 4.0.0 + + cdi-skipping-analyzer + + + + jakarta.ws.rs + jakarta.ws.rs-api + + + jakarta.annotation + jakarta.annotation-api + + + jakarta.enterprise + jakarta.enterprise.cdi-api + + + org.glassfish.jersey.ext.cdi + jersey-cdi1x + + + org.jboss.weld.se + weld-se-core + test + + + org.glassfish.jersey.test-framework + jersey-test-framework-util + test + + + org.glassfish.jersey.test-framework.providers + jersey-test-framework-provider-bundle + pom + test + + + org.glassfish.jersey.incubator + jersey-injectless-client + ${jersey.version} + + + diff --git a/tests/integration/cdi-integration/cdi-skipping-analyzer/src/main/java/org/glassfish/jersey/tests/cdi/skippinganalyzer/CdiService.java b/tests/integration/cdi-integration/cdi-skipping-analyzer/src/main/java/org/glassfish/jersey/tests/cdi/skippinganalyzer/CdiService.java new file mode 100644 index 0000000000..44d56d29dc --- /dev/null +++ b/tests/integration/cdi-integration/cdi-skipping-analyzer/src/main/java/org/glassfish/jersey/tests/cdi/skippinganalyzer/CdiService.java @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * 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.cdi.skippinganalyzer; + +public interface CdiService { + void doService(T t); +} diff --git a/tests/integration/cdi-integration/cdi-skipping-analyzer/src/main/java/org/glassfish/jersey/tests/cdi/skippinganalyzer/CdiServiceExtension.java b/tests/integration/cdi-integration/cdi-skipping-analyzer/src/main/java/org/glassfish/jersey/tests/cdi/skippinganalyzer/CdiServiceExtension.java new file mode 100644 index 0000000000..a7e5130ceb --- /dev/null +++ b/tests/integration/cdi-integration/cdi-skipping-analyzer/src/main/java/org/glassfish/jersey/tests/cdi/skippinganalyzer/CdiServiceExtension.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * 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.cdi.skippinganalyzer; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.event.Observes; +import jakarta.enterprise.inject.spi.AfterBeanDiscovery; +import jakarta.enterprise.inject.spi.Extension; +import java.io.IOException; + +public class CdiServiceExtension implements Extension { + public void observe(@Observes AfterBeanDiscovery event) throws IOException, ClassNotFoundException { + event.addBean() + .addType(CdiService.class) + .beanClass(CdiService.class) + .scope(ApplicationScoped.class) + .createWith(context -> new CdiServiceImpl()); + } + +} diff --git a/tests/integration/cdi-integration/cdi-skipping-analyzer/src/main/java/org/glassfish/jersey/tests/cdi/skippinganalyzer/CdiServiceImpl.java b/tests/integration/cdi-integration/cdi-skipping-analyzer/src/main/java/org/glassfish/jersey/tests/cdi/skippinganalyzer/CdiServiceImpl.java new file mode 100644 index 0000000000..640634688b --- /dev/null +++ b/tests/integration/cdi-integration/cdi-skipping-analyzer/src/main/java/org/glassfish/jersey/tests/cdi/skippinganalyzer/CdiServiceImpl.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * 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.cdi.skippinganalyzer; + +import jakarta.enterprise.inject.spi.BeanManager; +import jakarta.inject.Inject; + +public class CdiServiceImpl implements CdiService { + + @Inject + BeanManager beanManager; + + @Override + public void doService(StringBuilder sb) { + sb.append(getClass().getSimpleName()); + } +} diff --git a/tests/integration/cdi-integration/cdi-skipping-analyzer/src/main/java/org/glassfish/jersey/tests/cdi/skippinganalyzer/WeldDiscoveredBean.java b/tests/integration/cdi-integration/cdi-skipping-analyzer/src/main/java/org/glassfish/jersey/tests/cdi/skippinganalyzer/WeldDiscoveredBean.java new file mode 100644 index 0000000000..ce459d6449 --- /dev/null +++ b/tests/integration/cdi-integration/cdi-skipping-analyzer/src/main/java/org/glassfish/jersey/tests/cdi/skippinganalyzer/WeldDiscoveredBean.java @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * 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.cdi.skippinganalyzer; + +import jakarta.enterprise.context.ApplicationScoped; + +@ApplicationScoped +public class WeldDiscoveredBean { + +} diff --git a/tests/integration/cdi-integration/cdi-skipping-analyzer/src/main/resources/META-INF/beans.xml b/tests/integration/cdi-integration/cdi-skipping-analyzer/src/main/resources/META-INF/beans.xml new file mode 100644 index 0000000000..56ad04f3c1 --- /dev/null +++ b/tests/integration/cdi-integration/cdi-skipping-analyzer/src/main/resources/META-INF/beans.xml @@ -0,0 +1,24 @@ + + + + + + \ No newline at end of file diff --git a/tests/integration/cdi-integration/cdi-skipping-analyzer/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension b/tests/integration/cdi-integration/cdi-skipping-analyzer/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension new file mode 100644 index 0000000000..7bfc71c13c --- /dev/null +++ b/tests/integration/cdi-integration/cdi-skipping-analyzer/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension @@ -0,0 +1 @@ +org.glassfish.jersey.tests.cdi.skippinganalyzer.CdiServiceExtension \ No newline at end of file diff --git a/tests/integration/cdi-integration/cdi-skipping-analyzer/src/main/webapp/WEB-INF/web.xml b/tests/integration/cdi-integration/cdi-skipping-analyzer/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 0000000000..e038a3ab7f --- /dev/null +++ b/tests/integration/cdi-integration/cdi-skipping-analyzer/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,24 @@ + + + + + diff --git a/tests/integration/cdi-integration/cdi-skipping-analyzer/src/test/java/org/glassfish/jersey/tests/cdi/skippinganalyzer/SkippingAnalyzerTest.java b/tests/integration/cdi-integration/cdi-skipping-analyzer/src/test/java/org/glassfish/jersey/tests/cdi/skippinganalyzer/SkippingAnalyzerTest.java new file mode 100644 index 0000000000..698e496edc --- /dev/null +++ b/tests/integration/cdi-integration/cdi-skipping-analyzer/src/test/java/org/glassfish/jersey/tests/cdi/skippinganalyzer/SkippingAnalyzerTest.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * 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.cdi.skippinganalyzer; + +import org.glassfish.hk2.api.ClassAnalyzer; +import org.glassfish.jersey.ext.cdi1x.internal.CdiComponentProvider; +import org.glassfish.jersey.ext.cdi1x.internal.InjecteeSkippingAnalyzer; +import org.glassfish.jersey.inject.hk2.Hk2InjectionManagerFactory; +import org.glassfish.jersey.internal.inject.InjectionManager; +import org.glassfish.jersey.internal.inject.Injections; +import org.hamcrest.MatcherAssert; +import org.hamcrest.Matchers; +import org.jboss.weld.environment.se.Weld; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assumptions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import jakarta.enterprise.inject.spi.BeanManager; +import jakarta.enterprise.inject.spi.CDI; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.Map; +import java.util.Set; + +public class SkippingAnalyzerTest { + private Weld weld; + + @BeforeEach + public void setup() { + Assumptions.assumeTrue(Hk2InjectionManagerFactory.isImmediateStrategy()); + } + + @BeforeEach + public void setUp() throws Exception { + if (Hk2InjectionManagerFactory.isImmediateStrategy()) { + weld = new Weld(); + weld.initialize(); + } + } + + @AfterEach + public void tearDown() throws Exception { + weld.shutdown(); + } + + @Test + public void testInjecteeSkippingAnalyzerWithZeroFieldsToSkip() throws Exception { + BeanManager beanManager = CDI.current().getBeanManager(); + CdiComponentProvider provider = beanManager.getExtension(CdiComponentProvider.class); + Method method = provider.getClass().getDeclaredMethod("getFieldsToSkip"); + method.setAccessible(true); + Map fieldMap = (Map) method.invoke(provider); + MatcherAssert.assertThat(0, Matchers.is(fieldMap.size())); + + InjectionManager injectionManager = Injections.createInjectionManager(); + provider.initialize(injectionManager); + injectionManager.completeRegistration(); + ClassAnalyzer analyzer = injectionManager.getInstance(ClassAnalyzer.class, CdiComponentProvider.CDI_CLASS_ANALYZER); + MatcherAssert.assertThat(InjecteeSkippingAnalyzer.class, Matchers.is(analyzer.getClass())); + + Set fieldSet = analyzer.getFields(CdiServiceImpl.class); + MatcherAssert.assertThat(0, Matchers.is(fieldSet.size())); + } +} diff --git a/tests/integration/cdi-integration/pom.xml b/tests/integration/cdi-integration/pom.xml index a0b11ae2b9..6bf68e5945 100644 --- a/tests/integration/cdi-integration/pom.xml +++ b/tests/integration/cdi-integration/pom.xml @@ -43,6 +43,7 @@ cdi-multipart-webapp cdi-resource-with-at-context cdi-singleton + cdi-skipping-analyzer cdi-test-webapp cdi-with-jersey-injection-custom-cfg-webapp cdi-with-jersey-injection-custom-hk2-banned-webapp