Skip to content

Commit

Permalink
Refactor Contract for use with Reflection and Annotation Processing (#68
Browse files Browse the repository at this point in the history
)

Removing Class and any reflection based references in the TargetMethodDefinition and TargetDefintion classes to allow them to be able to be used by both runtime and compile time Contract parsing.

Additional Changes
---
Remove URI handling from Target and replace with a
User Supplied `Consumer` instance that allows for more customization
  • Loading branch information
kdavisk6 authored Jun 1, 2021
1 parent f4d0a52 commit 9aa37eb
Show file tree
Hide file tree
Showing 43 changed files with 866 additions and 893 deletions.
12 changes: 9 additions & 3 deletions core/src/main/java/feign/Contract.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2019-2020 OpenFeign Contributors
* Copyright 2019-2021 OpenFeign Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -16,14 +16,20 @@

package feign;

import java.util.Collection;
import feign.contract.TargetDefinition;

/**
* Represents the agreement between the specific implementation and the user, enforcing how
* each Target method can be defined.
*/
public interface Contract {

Collection<TargetMethodDefinition> apply(Target<?> target);
/**
* Create a new {@link TargetDefinition} from the {@link FeignConfiguration} provided.
*
* @param targetType with the Target configuration.
* @return a new {@link TargetDefinition} instance.
*/
TargetDefinition apply(Class<?> targetType, FeignConfiguration configuration);

}
35 changes: 19 additions & 16 deletions core/src/main/java/feign/Feign.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2019-2020 OpenFeign Contributors
* Copyright 2019-2021 OpenFeign Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -23,15 +23,15 @@
import feign.http.client.UrlConnectionClient;
import feign.impl.AbstractFeignConfigurationBuilder;
import feign.impl.BaseFeignConfiguration;
import feign.impl.UriTarget;
import feign.logging.SimpleLogger;
import feign.proxy.ProxyFeign;
import feign.retry.NoRetry;
import java.net.URI;

/**
* Feign instance builder. Provides access to a {@link FeignConfigurationBuilder}, using a
* fluent-api to allow user's to configure each component of a {@link FeignConfiguration}
* that will be used when executing methods on the {@link Target}.
* fluent-api to allow user's to configure each component of a {@link FeignConfiguration} that will
* be used when executing methods on the {@link Target}.
*/
public abstract class Feign {

Expand All @@ -40,32 +40,37 @@ public abstract class Feign {
*
* @return FeignConfigurationBuilder instance.
*/
public static FeignConfigurationBuilderImpl builder() {
return new FeignConfigurationBuilderImpl();
public static FeignConfigurationBuilderImpl builder(Class<?> targetType) {
return new FeignConfigurationBuilderImpl(targetType);
}

/**
* Creates a new instance of the {@link Target} type in the configuration. Implementations are
* expected to be thread-safe.
*
* @param targetType with the target type class.
* @param configuration containing the dependencies the resulting target should use.
* @param <T> of the Target.
* @return a new Target instance.
*/
protected abstract <T> T create(FeignConfiguration configuration);
protected abstract <T> T create(Class<?> targetType, FeignConfiguration configuration);

/**
* Default {@link FeignConfigurationBuilder}. Provides access to the core Feign components.
*/
static class FeignConfigurationBuilderImpl extends
public static class FeignConfigurationBuilderImpl extends
AbstractFeignConfigurationBuilder<FeignConfigurationBuilderImpl, FeignConfiguration> {

private final Class<?> targetType;

/**
* Creates a new Builder, defining the default components.
*/
FeignConfigurationBuilderImpl() {
FeignConfigurationBuilderImpl(Class<?> targetType) {
super(FeignConfigurationBuilderImpl.class);

this.targetType = targetType;

/* use the Feign Contract annotations. */
this.contract = new FeignContract();

Expand Down Expand Up @@ -96,25 +101,23 @@ static class FeignConfigurationBuilderImpl extends
*/
@Override
public FeignConfiguration build() {
return new BaseFeignConfiguration(
this.target, this.contract, this.encoder, this.interceptors, this.client, this.decoder,
this.exceptionHandler, this.executor, this.logger, this.retry);
return new BaseFeignConfiguration(this);
}

/**
* Creates a new JDK Proxy backed Target instance.
*
* @param targetType containing the Target definition.
* @param uri for all requests in the target to be sent to. Must be absolute.
* @param <T> type of the Target instance.
* @return a new Target instance.
*/
public <T> T target(Class<T> targetType, String uri) {
this.target(new UriTarget<>(targetType, uri));
public <T> T target(String uri) {
/* create a new Uri Supplier from the static value */
this.target(URI.create(uri));

/* create a new ProxyFeign instance */
Feign feign = new ProxyFeign();
return feign.create(this.build());
return feign.create(this.targetType, this.build());
}
}
}
19 changes: 10 additions & 9 deletions core/src/main/java/feign/FeignConfiguration.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2019-2020 OpenFeign Contributors
* Copyright 2019-2021 OpenFeign Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -16,14 +16,23 @@

package feign;

import feign.http.RequestSpecification;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.function.Consumer;

/**
* Configuration Definition.
*/
public interface FeignConfiguration {

/**
* Consumer that targets a request.
*
* @return a uri supplier.
*/
Consumer<RequestSpecification> getTarget();

/**
* Client instance to use to execute requests.
*
Expand Down Expand Up @@ -73,14 +82,6 @@ public interface FeignConfiguration {
*/
ExceptionHandler getExceptionHandler();

/**
* Target instance for this configuration.
*
* @param <T> type of the Target.
* @return the Target instance.
*/
<T> Target<T> getTarget();

/**
* Logger to use when logging request and responses.
*
Expand Down
31 changes: 21 additions & 10 deletions core/src/main/java/feign/FeignConfigurationBuilder.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2019-2020 OpenFeign Contributors
* Copyright 2019-2021 OpenFeign Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -16,17 +16,36 @@

package feign;

import feign.http.RequestSpecification;
import java.net.URI;
import java.util.concurrent.Executor;
import java.util.function.Consumer;

/**
* Configuration Builder Definition for any Feign instance.
*
* @param <B> type of Builder to chain.
* @param <C> type of FeignConfiguration to generate.
*/
public interface FeignConfigurationBuilder<B extends FeignConfigurationBuilder,
public interface FeignConfigurationBuilder<B extends FeignConfigurationBuilder<B, C>,
C extends FeignConfiguration> {

/**
* Consumer that returns "targets" a request.
*
* @param target with the base URI.
* @return the builder chain.
*/
B target(Consumer<RequestSpecification> target);

/**
* Default Base URI Target.
*
* @param baseUri as URI.
* @return the builder for chaining.
*/
B target(URI baseUri);

/**
* Request Encoder to use.
*
Expand Down Expand Up @@ -75,14 +94,6 @@ public interface FeignConfigurationBuilder<B extends FeignConfigurationBuilder,
*/
B contract(Contract contract);

/**
* Target to build off.
*
* @param target instance.
* @return the builder chain.
*/
B target(Target<?> target);

/**
* Exception Handler to use.
*
Expand Down
5 changes: 4 additions & 1 deletion core/src/main/java/feign/RequestOptions.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2019-2020 OpenFeign Contributors
* Copyright 2019-2021 OpenFeign Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -68,6 +68,9 @@ public static Builder builder() {
return new Builder();
}

/**
* Builder for creating new Request Options.
*/
public static class Builder {
private boolean followRedirects = true;
private long readTimeout = DEFAULT_READ_TIMEOUT;
Expand Down
5 changes: 4 additions & 1 deletion core/src/main/java/feign/Retry.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2019-2020 OpenFeign Contributors
* Copyright 2019-2021 OpenFeign Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -18,6 +18,9 @@

import java.util.function.Function;

/**
* Retry Handler interface.
*/
public interface Retry {

Response execute(
Expand Down
8 changes: 1 addition & 7 deletions core/src/main/java/feign/Target.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2019-2020 OpenFeign Contributors
* Copyright 2019-2021 OpenFeign Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -39,10 +39,4 @@ public interface Target<T> {
*/
String name();

/**
* "Target"s the specification.
*
* @param requestSpecification to target.
*/
void apply(RequestSpecification requestSpecification);
}
4 changes: 3 additions & 1 deletion core/src/main/java/feign/TargetMethodHandlerFactory.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2019-2020 OpenFeign Contributors
* Copyright 2019-2021 OpenFeign Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -16,6 +16,8 @@

package feign;

import feign.contract.TargetMethodDefinition;

/**
* Factory that creates TargetMethodHandler instances.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,11 @@
package feign.contract;

import feign.Contract;
import feign.Target;
import feign.TargetMethodDefinition;
import feign.FeignConfiguration;
import feign.contract.TargetDefinition.TargetDefinitionBuilder;
import feign.impl.type.TypeDefinitionFactory;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand All @@ -36,26 +34,32 @@ public abstract class AbstractAnnotationDrivenContract implements Contract {
private static final Logger logger =
LoggerFactory.getLogger(AbstractAnnotationDrivenContract.class);

protected final TypeDefinitionFactory typeDefinitionFactory = new TypeDefinitionFactory();

/**
* Using the Contract annotations, process the Target and create the appropriate
* {@link TargetMethodDefinition}s.
* Processes the {@link FeignConfiguration} and generate a new {@link TargetDefinition} instance.
*
* @param target to apply this contract to.
* @return a Collection of {@link TargetMethodDefinition}s with each methods configuration.
* @param targetType with the Target configuration.
* @return a new {@link TargetDefinition} instance.
*/
@Override
public Collection<TargetMethodDefinition> apply(Target<?> target) {
Set<TargetMethodDefinition> methods = new LinkedHashSet<>();
public TargetDefinition apply(Class<?> targetType, FeignConfiguration configuration) {

TargetDefinitionBuilder builder = TargetDefinition.builder()
.setTargetPackageName(targetType.getPackageName())
.setFullQualifiedTargetClassName(targetType.getName())
.setTargetTypeName(targetType.getSimpleName());

/* special metadata object tha contains the class level configuration that will be
* used by all methods on this target.
*/
Class<?> targetType = target.type();
TargetMethodDefinition.Builder builder = TargetMethodDefinition.builder(target);
for (Class<?> extension : targetType.getInterfaces()) {
builder.withExtension(extension.getCanonicalName());
}

logger.debug("Applying Contract to {}", targetType.getSimpleName());
this.processAnnotationsOnType(targetType, builder);
TargetMethodDefinition root = builder.build();
/* create the default method metadata from any annotations on the interface itself */
TargetMethodDefinition.Builder rootMethodBuilder = TargetMethodDefinition
.builder(targetType.getName())
.target(configuration.getTarget());
this.processAnnotationsOnType(targetType, rootMethodBuilder);
TargetMethodDefinition root = rootMethodBuilder.build();

for (Method method : targetType.getMethods()) {
/* create a new metadata object from the root */
Expand Down Expand Up @@ -98,18 +102,17 @@ public Collection<TargetMethodDefinition> apply(Target<?> target) {
}

if (!methodMetadata.isEmpty()) {
methods.add(methodMetadata);
builder.withTargetMethodDefinition(methodMetadata);
}
}
logger.debug("Contract parsing completed. Identified {} methods: [{}]",
methods.size(), methods);
return methods;

return builder.build();
}

/**
* Apply any Annotations located at the Type level. Any definitions applied at this level will
* be used as defaults for all methods on the target, unless redefined at the method or
* parameter level.
* Apply any Annotations located at the Type level. Any definitions applied at this level will be
* used as defaults for all methods on the target, unless redefined at the method or parameter
* level.
*
* @param targetType to inspect.
* @param targetMethodDefinitionBuilder to store the applied configuration.
Expand Down
Loading

0 comments on commit 9aa37eb

Please sign in to comment.