All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.github.belgif.rest.problem.jaxrs.client.ProblemSupport Maven / Gradle / Ivy

The newest version!
package io.github.belgif.rest.problem.jaxrs.client;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

import javax.ws.rs.client.AsyncInvoker;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.Invocation;
import javax.ws.rs.client.WebTarget;

/**
 * Utility class for enabling problem support on JAX-RS Clients.
 */
public class ProblemSupport {

    private ProblemSupport() {
        throw new IllegalStateException("Utility class");
    }

    /**
     * Enable problem support on the given JAX-RS Client.
     *
     * 

* This causes the JAX-RS Client to throw Problem exceptions instead of ProblemWrapper exceptions. *

* * @param client the JAX-RS Client * @return the problem-enabled JAX-RS Client */ public static Client enable(Client client) { if (!client.getConfiguration().isRegistered(ProblemClientResponseFilter.class)) { client.register(ProblemClientResponseFilter.class); } return createProxy(Client.class, new ClientInvocationHandler(client)); } /** * Enable problem support on the given client (e.g. RESTEasy proxy client). * *

* This causes the client to throw Problem exceptions instead of ProblemWrapper exceptions. *

* * @param client the client * @param the client type * @return the problem-enabled client */ @SuppressWarnings("unchecked") public static T enable(T client) { return (T) Proxy.newProxyInstance(ProblemSupport.class.getClassLoader(), client.getClass().getInterfaces(), new ProxyInvocationHandler(client)); } /** * JDK Dynamic Proxy InvocationHandler for JAX-RS Client. */ static final class ClientInvocationHandler implements InvocationHandler { private static final List> PROXIED_RETURN_TYPES = Arrays.asList( Client.class, WebTarget.class, Invocation.Builder.class, Invocation.class, AsyncInvoker.class, Future.class); private final Object target; ClientInvocationHandler(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object result; try { result = method.invoke(target, args); } catch (InvocationTargetException e) { if (e.getTargetException() instanceof ProblemWrapper) { throw ((ProblemWrapper) e.getTargetException()).getProblem(); } else if (e.getTargetException() instanceof ExecutionException) { ExecutionException executionException = (ExecutionException) e.getTargetException(); if (executionException.getCause() instanceof ProblemWrapper) { throw ((ProblemWrapper) executionException.getCause()).getProblem(); } } throw e.getTargetException(); } if (result == target) { return proxy; } if (result != null) { Optional> returnTypeToProxy = PROXIED_RETURN_TYPES.stream() .filter(t -> t.isAssignableFrom(result.getClass())) .findFirst(); if (returnTypeToProxy.isPresent()) { try { return createProxy(returnTypeToProxy.get(), new ClientInvocationHandler(method.invoke(target, args))); } catch (InvocationTargetException e) { throw e.getTargetException(); } } } return result; } } /** * JDK Dynamic Proxy InvocationHandler for proxy clients. */ static final class ProxyInvocationHandler implements InvocationHandler { private final Object target; ProxyInvocationHandler(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { try { return method.invoke(target, args); } catch (InvocationTargetException e) { if (e.getTargetException() instanceof ProblemWrapper) { throw ((ProblemWrapper) e.getTargetException()).getProblem(); } throw e.getTargetException(); } } } @SuppressWarnings("unchecked") private static T createProxy(Class intf, InvocationHandler invocationHandler) { return (T) Proxy.newProxyInstance(ProblemSupport.class.getClassLoader(), new Class[] { intf }, invocationHandler); } // TODO: What about methods that receive an javax.ws.rs.client.InvocationCallback? // Should we pass a Problem to the .failed() method instead of ProblemWrapper? // TODO: What about RxInvoker? javax.ws.rs.client.Invocation.Builder.rx() }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy