Skip to content

Commit

Permalink
Add MP Rest Client to jersey-bom
Browse files Browse the repository at this point in the history
Simplify CDI Extension
The default injection can be solved by explicitly specifying qualifiers Default and Any
Prefer looking up BeanManager in JNDI
This aligns the behavior with DefaultBeanManagerProvider and also works better
in more complicated classloader constellations.
Support Boolean in PrimitiveValueOfInserter

Signed-off-by: Patrik Dudits <patrik.dudits@payara.fish>
  • Loading branch information
pdudits authored and Verdent committed Jun 11, 2019
1 parent 00f804c commit 7b4cfa2
Show file tree
Hide file tree
Showing 9 changed files with 109 additions and 115 deletions.
5 changes: 5 additions & 0 deletions bom/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,11 @@
<artifactId>jersey-rx-client-rxjava2</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.ext</groupId>
<artifactId>jersey-mp-rest-client</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-jaxb</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2010, 2017 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018 Payara Foundation and/or its affiliates.
* Copyright (c) 2018, 2019 Payara Foundation and/or its affiliates.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
Expand All @@ -26,9 +26,10 @@
* @author Paul Sandoz
* @author Marek Potociar (marek.potociar at oracle.com)
* @author Gaurav Gupta (gaurav.gupta@payara.fish)
* @author Patrik Dudits
*
*/
final class PrimitiveValueOfInserter implements ParameterInserter<Number, String> {
final class PrimitiveValueOfInserter implements ParameterInserter<Object, String> {

private final String parameter;
private final String defaultValue;
Expand Down Expand Up @@ -61,7 +62,7 @@ public String getDefaultValueString() {
}

@Override
public String insert(Number value) {
public String insert(Object value) {
if (value != null) {
return value.toString();
} else if (defaultValue != null) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2019 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019 Payara Foundation 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
Expand Down Expand Up @@ -50,6 +51,7 @@
* Model of interface and its annotation.
*
* @author David Kral
* @author Patrik Dudits
*/
class InterfaceModel {

Expand All @@ -66,6 +68,7 @@ class InterfaceModel {
private final Set<ResponseExceptionMapper> responseExceptionMappers;
private final Set<ParamConverterProvider> paramConverterProviders;
private final Set<Annotation> interceptorAnnotations;
private final BeanManager beanManager;

/**
* Creates new model based on interface class. Interface is parsed according to specific annotations.
Expand All @@ -81,12 +84,14 @@ static InterfaceModel from(Class<?> restClientClass,
Set<ResponseExceptionMapper> responseExceptionMappers,
Set<ParamConverterProvider> paramConverterProviders,
List<AsyncInvocationInterceptor> asyncInterceptors,
InjectionManager injectionManager) {
InjectionManager injectionManager,
BeanManager beanManager) {
return new Builder(restClientClass,
responseExceptionMappers,
paramConverterProviders,
asyncInterceptors,
injectionManager)
injectionManager,
beanManager)
.pathValue(restClientClass.getAnnotation(Path.class))
.produces(restClientClass.getAnnotation(Produces.class))
.consumes(restClientClass.getAnnotation(Consumes.class))
Expand All @@ -108,6 +113,7 @@ private InterfaceModel(Builder builder) {
this.interceptorAnnotations = builder.interceptorAnnotations;
this.creationalContext = builder.creationalContext;
this.asyncInterceptors = builder.asyncInterceptors;
this.beanManager = builder.beanManager;
}

/**
Expand Down Expand Up @@ -237,11 +243,16 @@ Object resolveParamValue(Object arg, Parameter parameter) {
return arg;
}

BeanManager getBeanManager() {
return beanManager;
}

private static class Builder {

private final Class<?> restClientClass;

private final InjectionManager injectionManager;
private final BeanManager beanManager;
private String pathValue;
private String[] produces;
private String[] consumes;
Expand All @@ -257,30 +268,27 @@ private Builder(Class<?> restClientClass,
Set<ResponseExceptionMapper> responseExceptionMappers,
Set<ParamConverterProvider> paramConverterProviders,
List<AsyncInvocationInterceptor> asyncInterceptors,
InjectionManager injectionManager) {
InjectionManager injectionManager,
BeanManager beanManager) {
this.injectionManager = injectionManager;
this.restClientClass = restClientClass;
this.responseExceptionMappers = responseExceptionMappers;
this.paramConverterProviders = paramConverterProviders;
this.asyncInterceptors = asyncInterceptors;
this.beanManager = beanManager;
filterAllInterceptorAnnotations();
}

private void filterAllInterceptorAnnotations() {
creationalContext = null;
interceptorAnnotations = new HashSet<>();
try {
if (CDI.current() != null) {
BeanManager beanManager = CDI.current().getBeanManager();
creationalContext = beanManager.createCreationalContext(null);
for (Annotation annotation : restClientClass.getAnnotations()) {
if (beanManager.isInterceptorBinding(annotation.annotationType())) {
interceptorAnnotations.add(annotation);
}
if (beanManager != null) {
creationalContext = beanManager.createCreationalContext(null);
for (Annotation annotation : restClientClass.getAnnotations()) {
if (beanManager.isInterceptorBinding(annotation.annotationType())) {
interceptorAnnotations.add(annotation);
}
}
} catch (IllegalStateException ignored) {
//CDI not present. Ignore.
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2019 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019 Payara Foundation 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
Expand Down Expand Up @@ -39,7 +40,6 @@
import java.util.stream.Collectors;

import javax.enterprise.inject.spi.BeanManager;
import javax.enterprise.inject.spi.CDI;
import javax.enterprise.inject.spi.InterceptionType;
import javax.enterprise.inject.spi.Interceptor;
import javax.json.JsonValue;
Expand Down Expand Up @@ -74,6 +74,7 @@
* Method model contains all information about method defined in rest client interface.
*
* @author David Kral
* @author Patrik Dudits
*/
class MethodModel {

Expand Down Expand Up @@ -127,7 +128,8 @@ private MethodModel(Builder builder) {
interfaceModel.getResponseExceptionMappers(),
interfaceModel.getParamConverterProviders(),
interfaceModel.getAsyncInterceptors(),
interfaceModel.getInjectionManager());
interfaceModel.getInjectionManager(),
interfaceModel.getBeanManager());
} else {
subResourceModel = null;
}
Expand Down Expand Up @@ -475,35 +477,31 @@ private Builder(InterfaceModel interfaceModel, Method method) {

private void filterAllInterceptorAnnotations() {
invocationInterceptors = new ArrayList<>();
try {
if (CDI.current() != null) {
Set<Annotation> interceptorAnnotations = new HashSet<>();
BeanManager beanManager = CDI.current().getBeanManager();
for (Annotation annotation : method.getAnnotations()) {
if (beanManager.isInterceptorBinding(annotation.annotationType())) {
interceptorAnnotations.add(annotation);
}
}
interceptorAnnotations.addAll(interfaceModel.getInterceptorAnnotations());
Annotation[] allInterceptorAnnotations = interceptorAnnotations.toArray(new Annotation[0]);
if (allInterceptorAnnotations.length == 0) {
return;
BeanManager beanManager = interfaceModel.getBeanManager();
if (beanManager != null) {
Set<Annotation> interceptorAnnotations = new HashSet<>();
for (Annotation annotation : method.getAnnotations()) {
if (beanManager.isInterceptorBinding(annotation.annotationType())) {
interceptorAnnotations.add(annotation);
}
List<Interceptor<?>> interceptors = beanManager.resolveInterceptors(InterceptionType.AROUND_INVOKE,
allInterceptorAnnotations);
if (!interceptors.isEmpty()) {
for (Interceptor<?> interceptor : interceptors) {
Object interceptorInstance = beanManager.getReference(interceptor,
interceptor.getBeanClass(),
interfaceModel.getCreationalContext());
invocationInterceptors.add(new InterceptorInvocationContext
.InvocationInterceptor(interceptorInstance,
interceptor));
}
}
interceptorAnnotations.addAll(interfaceModel.getInterceptorAnnotations());
Annotation[] allInterceptorAnnotations = interceptorAnnotations.toArray(new Annotation[0]);
if (allInterceptorAnnotations.length == 0) {
return;
}
List<Interceptor<?>> interceptors = beanManager.resolveInterceptors(InterceptionType.AROUND_INVOKE,
allInterceptorAnnotations);
if (!interceptors.isEmpty()) {
for (Interceptor<?> interceptor : interceptors) {
Object interceptorInstance = beanManager.getReference(interceptor,
interceptor.getBeanClass(),
interfaceModel.getCreationalContext());
invocationInterceptors.add(new InterceptorInvocationContext
.InvocationInterceptor(interceptorInstance,
interceptor));
}
}
} catch (IllegalStateException ignored) {
//CDI not present. Ignore.
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2019 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019 Payara Foundation 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
Expand Down Expand Up @@ -36,6 +37,11 @@
import java.util.stream.Collectors;

import javax.annotation.Priority;
import javax.enterprise.inject.spi.BeanManager;
import javax.enterprise.inject.spi.CDI;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.ws.rs.Priorities;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
Expand All @@ -55,7 +61,6 @@
import org.eclipse.microprofile.rest.client.ext.ResponseExceptionMapper;
import org.eclipse.microprofile.rest.client.spi.RestClientListener;
import org.glassfish.jersey.client.Initializable;
import org.glassfish.jersey.client.JerseyClient;
import org.glassfish.jersey.internal.inject.InjectionManager;
import org.glassfish.jersey.internal.inject.InjectionManagerSupplier;
import org.glassfish.jersey.internal.util.ReflectionHelper;
Expand All @@ -64,6 +69,7 @@
* Rest client builder implementation. Creates proxy instance of requested interface.
*
* @author David Kral
* @author Patrik Dudits
*/
public class RestClientBuilderImpl implements RestClientBuilder {

Expand Down Expand Up @@ -183,7 +189,8 @@ public <T> T build(Class<T> interfaceClass) throws IllegalStateException, RestCl
responseExceptionMappers,
paramConverterProviders,
asyncInterceptors,
injectionManagerExposer.injectionManager);
injectionManagerExposer.injectionManager,
lookupBeanManager());


return (T) Proxy.newProxyInstance(interfaceClass.getClassLoader(),
Expand All @@ -192,6 +199,31 @@ public <T> T build(Class<T> interfaceClass) throws IllegalStateException, RestCl
);
}

private BeanManager lookupBeanManager() {
Context initialContext = null;
try {
initialContext = new InitialContext();
return (BeanManager) initialContext.lookup("java:comp/BeanManager");
} catch (NamingException e) {
// no bean manager in JNDI
} finally {
if (initialContext != null) {
try {
initialContext.close();
} catch (NamingException e) {
}
}
}
try {
if (CDI.current() != null) {
return CDI.current().getBeanManager();
}
} catch (IllegalStateException e) {
// CDI unavailable
}
return null;
}

private void processConfigProviders(Class<?> restClientInterface, String[] providerArray) {
for (String provider : providerArray) {
Class<?> providerClass = AccessController.doPrivileged(ReflectionHelper.classForNamePA(provider));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,64 +71,14 @@ public void collectClientRegistrations(@Observes
}
}

/**
* Iterates over all {@link ProcessInjectionPoint} to find only those annotated
* with {@link RestClient} and configures their proper injection.
*
* @param pip processed injection point
*/
public void collectClientProducer(@Observes ProcessInjectionPoint<?, ?> pip) {
RestClient restClient = pip.getInjectionPoint().getAnnotated().getAnnotation(RestClient.class);
if (restClient != null) {
InjectionPoint ip = pip.getInjectionPoint();
Class<?> type = (Class<?>) ip.getType();

RestClientLiteral q = new RestClientLiteral(type);

pip.configureInjectionPoint().addQualifier(q);
}
}

/**
* Creates new producers based on collected interfaces.
*
* @param abd after bean discovery instance
* @param bm bean manager instance
*/
public void restClientRegistration(@Observes AfterBeanDiscovery abd, BeanManager bm) {
interfaces.forEach(type -> abd.addBean(new RestClientProducer(new RestClientLiteral(type), type, bm)));
interfaces.forEach(type -> abd.addBean(new RestClientProducer(null, type, bm)));
}

@Qualifier
@Retention(RUNTIME)
@Target({METHOD, FIELD})
@interface MpRestClientQualifier {

Class<?> interfaceType();

}

private static class RestClientLiteral extends AnnotationLiteral<MpRestClientQualifier> implements MpRestClientQualifier {

private final Class<?> interfaceType;

RestClientLiteral(Class<?> interfaceType) {
this.interfaceType = interfaceType;
}

@Override
public Class<?> interfaceType() {
return interfaceType;
}

@Override
public String toString() {
return "RestClientLiteral{"
+ "interfaceType=" + interfaceType
+ '}';
}

interfaces.forEach(type -> abd.addBean(new RestClientProducer(type, bm)));
}

}
Loading

0 comments on commit 7b4cfa2

Please sign in to comment.