From 7067d237418d76ba0c8fdfff66fd87d3df5bd4a1 Mon Sep 17 00:00:00 2001 From: facarvalho Date: Tue, 6 Jul 2021 21:30:23 -0500 Subject: [PATCH] Adding new Encoder type --- .../main/java/feign/DeclarativeContract.java | 2 +- core/src/main/java/feign/ReflectiveFeign.java | 20 +++++-- .../feign/codec/UnconditionalEncoder.java | 55 +++++++++++++++++++ 3 files changed, 72 insertions(+), 5 deletions(-) create mode 100644 core/src/main/java/feign/codec/UnconditionalEncoder.java diff --git a/core/src/main/java/feign/DeclarativeContract.java b/core/src/main/java/feign/DeclarativeContract.java index adf7dc7b3..3788a164f 100644 --- a/core/src/main/java/feign/DeclarativeContract.java +++ b/core/src/main/java/feign/DeclarativeContract.java @@ -43,7 +43,7 @@ public final List parseAndValidateMetadata(Class targetType) * (unless they are the same). * * @param data metadata collected so far relating to the current java method. - * @param clz the class to process + * @param targetType the class to process */ @Override protected final void processAnnotationOnClass(MethodMetadata data, Class targetType) { diff --git a/core/src/main/java/feign/ReflectiveFeign.java b/core/src/main/java/feign/ReflectiveFeign.java index c067c4909..03f08a2d6 100644 --- a/core/src/main/java/feign/ReflectiveFeign.java +++ b/core/src/main/java/feign/ReflectiveFeign.java @@ -155,7 +155,7 @@ public Map apply(Target target) { if (!md.formParams().isEmpty() && md.template().bodyTemplate() == null) { buildTemplate = new BuildFormEncodedTemplateFromArgs(md, encoder, queryMapEncoder, target); - } else if (md.bodyIndex() != null) { + } else if (md.bodyIndex() != null || UnconditionalEncoder.class.isAssignableFrom(encoder.getClass())) { buildTemplate = new BuildEncodedTemplateFromArgs(md, encoder, queryMapEncoder, target); } else { buildTemplate = new BuildTemplateByResolvingArgs(md, queryMapEncoder, target); @@ -379,10 +379,22 @@ private BuildEncodedTemplateFromArgs(MethodMetadata metadata, Encoder encoder, protected RequestTemplate resolve(Object[] argv, RequestTemplate mutable, Map variables) { - Object body = argv[metadata.bodyIndex()]; - checkArgument(body != null, "Body parameter %s was null", metadata.bodyIndex()); + + boolean unconditionalEncoder = UnconditionalEncoder.class.isAssignableFrom(encoder.getClass()); + + Object body = null; + if (!unconditionalEncoder) { + body = argv[metadata.bodyIndex()]; + checkArgument(body != null, "Body parameter %s was null", metadata.bodyIndex()); + } + try { - encoder.encode(body, metadata.bodyType(), mutable); + if (unconditionalEncoder) { + UnconditionalEncoder unEncoder = (UnconditionalEncoder) encoder; + unEncoder.encode(argv, mutable); + } else { + encoder.encode(body, metadata.bodyType(), mutable); + } } catch (EncodeException e) { throw e; } catch (RuntimeException e) { diff --git a/core/src/main/java/feign/codec/UnconditionalEncoder.java b/core/src/main/java/feign/codec/UnconditionalEncoder.java new file mode 100644 index 000000000..26d6e23eb --- /dev/null +++ b/core/src/main/java/feign/codec/UnconditionalEncoder.java @@ -0,0 +1,55 @@ +/** + * Copyright 2012-2020 The Feign Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package feign.codec; + +import feign.RequestTemplate; +import java.lang.reflect.Type; + +/** + * {@link Encoder} extension that allows user provided custom encoders to define the request message + * payload using only the request template and the method parameters, not requiring a specific and + * unique body object. + * + * This type of encoder is useful when an application needs a Feign client whose request payload is + * defined entirely by a custom Feign encoder regardless of how many parameters are declared at the + * client method. In this case, even with no presence of body parameter the encoder will have to + * know how to define the request payload (for example, based on the method name, method return + * type, and other metadata provided by custom annotations, all available via the provided + * {@link RequestTemplate} object). + * + * @author fabiocarvalho777@gmail.com + */ +public interface UnconditionalEncoder extends Encoder { + + /** + * {@inheritDoc} + */ + @Override + default void encode(Object object, Type bodyType, RequestTemplate template) + throws EncodeException { + throw new UnsupportedOperationException( + "This encode method is not supported in this type of encoder, instead, use the overloaded version with parameters array and request template"); + } + + /** + * Produces message body exclusively based on the request template. + * + * @param parameters the values of the parameters passed by the client when calling the method, + * ordered according to parameters definition order. + * @param template the request template to populate. + * @throws EncodeException when encoding failed due to a checked exception. + */ + void encode(Object[] parameters, RequestTemplate template) throws EncodeException; + +}