Skip to content

Commit 86d2810

Browse files
committed
ServiceFinder defaults to ServiceLookupIteratorProvider
Signed-off-by: Jorge Bescos Gascon <[email protected]>
1 parent 2220c83 commit 86d2810

File tree

7 files changed

+188
-20
lines changed

7 files changed

+188
-20
lines changed

core-common/src/main/java/org/glassfish/jersey/internal/OsgiRegistry.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2012, 2020 Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2012, 2022 Oracle and/or its affiliates. All rights reserved.
33
*
44
* This program and the accompanying materials are made available under the
55
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -106,7 +106,7 @@ public static synchronized OsgiRegistry getInstance() {
106106

107107
private final class OsgiServiceFinder extends ServiceFinder.ServiceIteratorProvider {
108108

109-
final ServiceFinder.ServiceIteratorProvider defaultIterator = new ServiceFinder.DefaultServiceIteratorProvider();
109+
final ServiceFinder.ServiceIteratorProvider defaultIterator = new ServiceFinder.ServiceReflectionIteratorProvider();
110110

111111
@Override
112112
public <T> Iterator<T> createIterator(

core-common/src/main/java/org/glassfish/jersey/internal/ServiceFinder.java

Lines changed: 57 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2010, 2018 Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2010, 2022 Oracle and/or its affiliates. All rights reserved.
33
*
44
* This program and the accompanying materials are made available under the
55
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -31,10 +31,12 @@
3131
import java.util.Iterator;
3232
import java.util.List;
3333
import java.util.NoSuchElementException;
34+
import java.util.ServiceLoader;
3435
import java.util.Set;
3536
import java.util.TreeSet;
3637
import java.util.logging.Level;
3738
import java.util.logging.Logger;
39+
import java.util.stream.Collectors;
3840

3941
import org.glassfish.jersey.internal.util.ReflectionHelper;
4042

@@ -229,7 +231,9 @@ public static <T> ServiceFinder<T> find(final Class<T> service, final ClassLoade
229231
* class loader (or, failing that the bootstrap class loader) is to
230232
* be used
231233
* @param ignoreOnClassNotFound If a provider cannot be loaded by the class loader
232-
* then move on to the next available provider.
234+
* then move on to the next available provider. This value does
235+
* not apply when the {@link ServiceIteratorProvider} is set to
236+
* {@link ServiceLookupIteratorProvider}.
233237
* @throws ServiceConfigurationError If a provider-configuration file violates the specified format
234238
* or names a provider class that cannot be found and instantiated
235239
* @see #find(Class)
@@ -279,7 +283,10 @@ public static <T> ServiceFinder<T> find(final Class<T> service)
279283
* </pre>
280284
* @param service The service's abstract service class
281285
* @param ignoreOnClassNotFound If a provider cannot be loaded by the class loader
282-
* then move on to the next available provider.
286+
* then move on to the next available provider. This value does
287+
* not apply when the {@link ServiceIteratorProvider} is set to
288+
* {@link ServiceLookupIteratorProvider}.
289+
*
283290
* @throws ServiceConfigurationError If a provider-configuration file violates the specified format
284291
* or names a provider class that cannot be found and instantiated
285292
* @see #find(Class, ClassLoader)
@@ -312,7 +319,7 @@ public static ServiceFinder<?> find(final String serviceName) throws ServiceConf
312319
* Register the service iterator provider to iterate on provider instances
313320
* or classes.
314321
* <p>
315-
* The default implementation registered, {@link DefaultServiceIteratorProvider},
322+
* The default implementation registered, {@link ServiceLookupIteratorProvider},
316323
* looks up provider classes in META-INF/service files.
317324
* <p>
318325
* This method must be called prior to any attempts to obtain provider
@@ -790,7 +797,7 @@ private void handleClassNotFoundException() throws ServiceConfigurationError {
790797
* Supports iteration of provider instances or classes.
791798
* <p>
792799
* The default implementation looks up provider classes from META-INF/services
793-
* files, see {@link DefaultServiceIteratorProvider}.
800+
* files, see {@link ServiceLookupIteratorProvider}.
794801
* This implementation may be overridden by invoking
795802
* {@link ServiceFinder#setIteratorProvider(org.glassfish.jersey.internal.ServiceFinder.ServiceIteratorProvider)}.
796803
*/
@@ -806,7 +813,7 @@ private static ServiceIteratorProvider getInstance() {
806813
synchronized (sipLock) {
807814
result = sip;
808815
if (result == null) { // Second check (with locking)
809-
sip = result = new DefaultServiceIteratorProvider();
816+
sip = result = new ServiceLookupIteratorProvider();
810817
}
811818
}
812819
}
@@ -834,7 +841,9 @@ private static void setInstance(final ServiceIteratorProvider sip) throws Securi
834841
* classes.
835842
* @param ignoreOnClassNotFound if true ignore an instance if the
836843
* corresponding provider class if cannot be found,
837-
* otherwise throw a {@link ClassNotFoundException}.
844+
* otherwise throw a {@link ClassNotFoundException}. This value does
845+
* not apply when the {@link ServiceIteratorProvider} is set to
846+
* {@link ServiceLookupIteratorProvider}.
838847
* @return the provider instance iterator.
839848
*/
840849
public abstract <T> Iterator<T> createIterator(Class<T> service,
@@ -851,6 +860,8 @@ public abstract <T> Iterator<T> createIterator(Class<T> service,
851860
* @param ignoreOnClassNotFound if true ignore the provider class if
852861
* cannot be found,
853862
* otherwise throw a {@link ClassNotFoundException}.
863+
* This value does not apply when the {@link ServiceIteratorProvider}
864+
* is set to {@link ServiceLookupIteratorProvider}.
854865
* @return the provider class iterator.
855866
*/
856867
public abstract <T> Iterator<Class<T>> createClassIterator(Class<T> service,
@@ -860,13 +871,10 @@ public abstract <T> Iterator<Class<T>> createClassIterator(Class<T> service,
860871
}
861872

862873
/**
863-
* The default service iterator provider that looks up provider classes in
874+
* The service iterator provider that looks up provider classes in
864875
* META-INF/services files.
865-
* <p>
866-
* This class may utilized if a {@link ServiceIteratorProvider} needs to
867-
* reuse the default implementation.
868876
*/
869-
public static final class DefaultServiceIteratorProvider extends ServiceIteratorProvider {
877+
public static final class ServiceReflectionIteratorProvider extends ServiceIteratorProvider {
870878

871879
@Override
872880
public <T> Iterator<T> createIterator(final Class<T> service, final String serviceName,
@@ -880,4 +888,41 @@ public <T> Iterator<Class<T>> createClassIterator(final Class<T> service, final
880888
return new LazyClassIterator<T>(service, serviceName, loader, ignoreOnClassNotFound);
881889
}
882890
}
891+
892+
/**
893+
* The service iterator provider that looks up provider classes in
894+
* META-INF/services files using {@link ServiceLoader}.
895+
*/
896+
public static final class ServiceLookupIteratorProvider extends ServiceIteratorProvider {
897+
898+
@Override
899+
public <T> Iterator<T> createIterator(final Class<T> service, final String serviceName,
900+
final ClassLoader loader, final boolean ignoreOnClassNotFound) {
901+
Class<T> clazz = fixGenericService(service, serviceName, loader, ignoreOnClassNotFound);
902+
return ServiceLoader.load(clazz, loader).iterator();
903+
}
904+
905+
@Override
906+
public <T> Iterator<Class<T>> createClassIterator(final Class<T> service, final String serviceName,
907+
final ClassLoader loader, final boolean ignoreOnClassNotFound) {
908+
Class<T> clazz = fixGenericService(service, serviceName, loader, ignoreOnClassNotFound);
909+
List<Class<T>> classes = ServiceLoader.load(clazz, loader).stream()
910+
.map(provider -> (Class<T>) provider.type())
911+
.collect(Collectors.toList());
912+
return classes.iterator();
913+
}
914+
915+
private <T> Class<T> fixGenericService(final Class<T> service, final String serviceName,
916+
final ClassLoader loader, final boolean ignoreOnClassNotFound) {
917+
Class<T> clazz = service;
918+
if (Object.class == service) {
919+
try {
920+
clazz = (Class<T>) ReflectionHelper.classForNameWithExceptionPEA(serviceName, loader).run();
921+
} catch (Exception e) {
922+
// Ignore it. Later, the service implementation will not be loaded.
923+
}
924+
}
925+
return clazz;
926+
}
927+
}
883928
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/*
2+
* Copyright (c) 2022 Oracle and/or its affiliates. All rights reserved.
3+
*
4+
* This program and the accompanying materials are made available under the
5+
* terms of the Eclipse Public License v. 2.0, which is available at
6+
* http://www.eclipse.org/legal/epl-2.0.
7+
*
8+
* This Source Code may also be made available under the following Secondary
9+
* Licenses when the conditions for such availability set forth in the
10+
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
11+
* version 2 with the GNU Classpath Exception, which is available at
12+
* https://www.gnu.org/software/classpath/license.html.
13+
*
14+
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15+
*/
16+
17+
package org.glassfish.jersey.server.internal;
18+
19+
public interface ServiceExample {}

core-server/src/test/java/org/glassfish/jersey/server/internal/ServiceFinderTest.java

Lines changed: 105 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2014, 2018 Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2014, 2022 Oracle and/or its affiliates. All rights reserved.
33
*
44
* This program and the accompanying materials are made available under the
55
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -16,29 +16,128 @@
1616

1717
package org.glassfish.jersey.server.internal;
1818

19+
import static org.glassfish.jersey.server.JarUtils.createJarFile;
20+
import static org.junit.Assert.assertEquals;
21+
import static org.junit.Assert.assertFalse;
22+
import static org.junit.Assert.assertTrue;
23+
import static org.junit.Assert.fail;
24+
1925
import java.io.IOException;
2026
import java.lang.reflect.Method;
2127
import java.net.URL;
2228
import java.net.URLClassLoader;
2329
import java.util.Collections;
2430
import java.util.HashMap;
2531
import java.util.HashSet;
32+
import java.util.Iterator;
2633
import java.util.Map;
2734
import java.util.Set;
2835

36+
import javax.ws.rs.container.DynamicFeature;
37+
import javax.ws.rs.core.Configurable;
38+
39+
import org.glassfish.jersey.internal.ServiceConfigurationError;
2940
import org.glassfish.jersey.internal.ServiceFinder;
41+
import org.glassfish.jersey.internal.ServiceFinder.ServiceIteratorProvider;
42+
import org.glassfish.jersey.internal.ServiceFinder.ServiceLookupIteratorProvider;
43+
import org.glassfish.jersey.internal.ServiceFinder.ServiceReflectionIteratorProvider;
3044
import org.glassfish.jersey.server.JarUtils;
31-
45+
import org.glassfish.jersey.server.JaxRsFeatureRegistrationTest.DynamicFeatureImpl;
46+
import org.junit.AfterClass;
3247
import org.junit.Test;
33-
import static org.glassfish.jersey.server.JarUtils.createJarFile;
34-
import static org.junit.Assert.assertEquals;
35-
import static org.junit.Assert.assertTrue;
3648

3749
/**
3850
* @author Michal Gajdos
3951
*/
4052
public class ServiceFinderTest {
4153

54+
@AfterClass
55+
public static void afterClass() {
56+
// Restore the default
57+
ServiceFinder.setIteratorProvider(null);
58+
}
59+
60+
@Test
61+
public void testExistingClass() {
62+
ServiceIteratorProvider[] providers = new ServiceIteratorProvider[] {
63+
new ServiceReflectionIteratorProvider(), new ServiceLookupIteratorProvider()};
64+
for (ServiceIteratorProvider provider : providers) {
65+
ServiceFinder.setIteratorProvider(provider);
66+
ServiceFinder<?> serviceFinder = ServiceFinder.find(DynamicFeature.class);
67+
checks(provider, serviceFinder);
68+
serviceFinder = ServiceFinder.find("javax.ws.rs.container.DynamicFeature");
69+
checks(provider, serviceFinder);
70+
}
71+
}
72+
73+
@Test
74+
public void testMissingService() {
75+
ServiceIteratorProvider[] providers = new ServiceIteratorProvider[] {
76+
new ServiceReflectionIteratorProvider(), new ServiceLookupIteratorProvider()};
77+
for (ServiceIteratorProvider provider : providers) {
78+
ServiceFinder.setIteratorProvider(provider);
79+
ServiceFinder<?> serviceFinder = ServiceFinder.find(Configurable.class);
80+
assertFalse(serviceFinder.iterator().hasNext());
81+
serviceFinder = ServiceFinder.find("javax.ws.rs.core.Configurable");
82+
assertFalse(serviceFinder.iterator().hasNext());
83+
}
84+
}
85+
86+
@Test
87+
public void testClassNotFound() {
88+
ServiceIteratorProvider[] providers = new ServiceIteratorProvider[] {
89+
new ServiceReflectionIteratorProvider(), new ServiceLookupIteratorProvider()};
90+
for (ServiceIteratorProvider provider : providers) {
91+
ServiceFinder.setIteratorProvider(provider);
92+
ServiceFinder<?> serviceFinder = ServiceFinder.find("doesNotExist");
93+
assertFalse(serviceFinder.iterator().hasNext());
94+
}
95+
}
96+
97+
@Test
98+
public void testServiceReflectionIteratorProviderImplementationNotFound() {
99+
ServiceFinder.setIteratorProvider(new ServiceReflectionIteratorProvider());
100+
ServiceFinder<?> serviceFinder = ServiceFinder.find(ServiceExample.class, true);
101+
assertFalse(serviceFinder.iterator().hasNext());
102+
serviceFinder = ServiceFinder.find(ServiceExample.class, false);
103+
try {
104+
serviceFinder.iterator().hasNext();
105+
fail("It is expected to fail");
106+
} catch (ServiceConfigurationError e) {
107+
// Expected
108+
}
109+
}
110+
111+
@Test
112+
public void testServiceLookupIteratorProviderImplementationNotFound() {
113+
ServiceFinder.setIteratorProvider(new ServiceLookupIteratorProvider());
114+
ServiceFinder<?> serviceFinder = ServiceFinder.find(ServiceExample.class, true);
115+
Iterator<?> iterator = serviceFinder.iterator();
116+
try {
117+
iterator.hasNext();
118+
iterator.next();
119+
fail("It is expected to fail");
120+
} catch (java.util.ServiceConfigurationError e) {
121+
// Expected
122+
}
123+
serviceFinder = ServiceFinder.find(ServiceExample.class, false);
124+
iterator = serviceFinder.iterator();
125+
try {
126+
iterator.hasNext();
127+
iterator.next();
128+
fail("It is expected to fail");
129+
} catch (java.util.ServiceConfigurationError e) {
130+
// Expected
131+
}
132+
}
133+
134+
private void checks(ServiceIteratorProvider provider, ServiceFinder<?> serviceFinder) {
135+
Iterator<?> iterator = serviceFinder.iterator();
136+
assertTrue("No instance found with " + provider, iterator.hasNext());
137+
Object dynamicFeature = iterator.next();
138+
assertEquals(DynamicFeatureImpl.class, dynamicFeature.getClass());
139+
}
140+
42141
@Test
43142
public void testJarTopLevel() throws Exception {
44143
final Map<String, String> map = new HashMap<>();
@@ -49,6 +148,7 @@ public void testJarTopLevel() throws Exception {
49148
final String path = ServiceFinderTest.class.getResource("").getPath();
50149
final ClassLoader classLoader = createClassLoader(path.substring(0, path.indexOf("org")), map);
51150

151+
ServiceFinder.setIteratorProvider(new ServiceReflectionIteratorProvider());
52152
final ServiceFinder<?> finder = createServiceFinder(classLoader, "jaxrs-components");
53153

54154
final Set<Class<?>> s = new HashSet<>();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
unknown

pom.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,7 @@
418418
-Xmx${surefire.maxmem.argline}m -Dfile.encoding=UTF8 ${surefire.security.argline} ${surefire.coverage.argline}
419419
</argLine>
420420
<skipTests>${skip.tests}</skipTests>
421+
<trimStackTrace>false</trimStackTrace>
421422
</configuration>
422423
<dependencies>
423424
<dependency>

tests/integration/jersey-2335/src/main/java/org/glassfish/jersey/tests/integration/jersey2335/ConstructorInjectedProvider.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2014, 2020 Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2014, 2022 Oracle and/or its affiliates. All rights reserved.
33
*
44
* This program and the accompanying materials are made available under the
55
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -48,6 +48,8 @@ public ConstructorInjectedProvider(@Context final Providers providers) {
4848
this.providers = providers;
4949
}
5050

51+
public ConstructorInjectedProvider() {}
52+
5153
@Override
5254
public boolean isWriteable(final Class<?> type, final Type genericType, final Annotation[] annotations,
5355
final MediaType mediaType) {

0 commit comments

Comments
 (0)