Skip to content

Commit f390818

Browse files
committed
Inline BaseContract
1 parent c40d77c commit f390818

4 files changed

Lines changed: 131 additions & 169 deletions

File tree

.palantir/revapi.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,9 @@ acceptedBreaks:
9292
\ java.lang.String)"
9393
justification: "Removed internal method"
9494
com.palantir.conjure.java.runtime:conjure-java-jaxrs-client:
95+
- code: "java.class.removed"
96+
old: "class com.palantir.conjure.java.client.jaxrs.CompatibleJaxRsContract"
97+
justification: "Class is package private"
9598
- code: "java.class.removed"
9699
old: "class com.palantir.conjure.java.client.jaxrs.feignimpl.CborDelegateDecoder"
97100
justification: "Removing Feign dependency and making internals private"

conjure-java-jaxrs-client/src/main/java/com/palantir/conjure/java/client/jaxrs/AbstractFeignJaxRsClientBuilder.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ public Request apply(RequestTemplate input) {
121121
}
122122

123123
private static Contract createContract() {
124-
Contract contract = new CompatibleJaxRsContract();
124+
Contract contract = new JaxRsContract();
125125
contract = new GuavaOptionalAwareContract(contract);
126126
contract = new Java8OptionalAwareContract(contract);
127127
contract = new SlashEncodingContract(contract);

conjure-java-jaxrs-client/src/main/java/com/palantir/conjure/java/client/jaxrs/Contract.java

Lines changed: 0 additions & 144 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,7 @@
1515
*/
1616
package com.palantir.conjure.java.client.jaxrs;
1717

18-
import java.lang.annotation.Annotation;
19-
import java.lang.reflect.Method;
20-
import java.lang.reflect.Modifier;
21-
import java.net.URI;
22-
import java.util.ArrayList;
23-
import java.util.Collection;
24-
import java.util.LinkedHashMap;
2518
import java.util.List;
26-
import java.util.Map;
2719

2820
/**
2921
* Defines what annotations and values are valid on interfaces.
@@ -37,140 +29,4 @@ interface Contract {
3729
* @param targetType {@link Target#type() type} of the Feign interface.
3830
*/
3931
List<MethodMetadata> parseAndValidateMetadata(Class<?> targetType);
40-
41-
abstract class BaseContract implements Contract {
42-
43-
@Override
44-
public List<MethodMetadata> parseAndValidateMetadata(Class<?> targetType) {
45-
Util.checkState(
46-
targetType.getTypeParameters().length == 0,
47-
"Parameterized types unsupported: %s",
48-
targetType.getSimpleName());
49-
Util.checkState(
50-
targetType.getInterfaces().length <= 1,
51-
"Only single inheritance supported: %s",
52-
targetType.getSimpleName());
53-
if (targetType.getInterfaces().length == 1) {
54-
Util.checkState(
55-
targetType.getInterfaces()[0].getInterfaces().length == 0,
56-
"Only single-level inheritance supported: %s",
57-
targetType.getSimpleName());
58-
}
59-
Map<String, MethodMetadata> result = new LinkedHashMap<String, MethodMetadata>();
60-
for (Method method : targetType.getMethods()) {
61-
if (method.getDeclaringClass() == Object.class
62-
|| (method.getModifiers() & Modifier.STATIC) != 0
63-
|| method.isDefault()) {
64-
continue;
65-
}
66-
MethodMetadata metadata = parseAndValidateMetadata(targetType, method);
67-
Util.checkState(
68-
!result.containsKey(metadata.configKey()), "Overrides unsupported: %s", metadata.configKey());
69-
result.put(metadata.configKey(), metadata);
70-
}
71-
return new ArrayList<MethodMetadata>(result.values());
72-
}
73-
74-
/**
75-
* Called indirectly by {@link #parseAndValidateMetadata(Class)}.
76-
*/
77-
MethodMetadata parseAndValidateMetadata(Class<?> targetType, Method method) {
78-
MethodMetadata data = new MethodMetadata();
79-
data.returnType(Types.resolve(targetType, targetType, method.getGenericReturnType()));
80-
data.configKey(Feign.configKey(targetType, method));
81-
82-
if (targetType.getInterfaces().length == 1) {
83-
processAnnotationOnClass(data, targetType.getInterfaces()[0]);
84-
}
85-
processAnnotationOnClass(data, targetType);
86-
87-
for (Annotation methodAnnotation : method.getAnnotations()) {
88-
processAnnotationOnMethod(data, methodAnnotation, method);
89-
}
90-
Util.checkState(
91-
data.template().method() != null,
92-
"Method %s not annotated with HTTP method type (ex. GET, POST)",
93-
method.getName());
94-
Class<?>[] parameterTypes = method.getParameterTypes();
95-
96-
Annotation[][] parameterAnnotations = method.getParameterAnnotations();
97-
int count = parameterAnnotations.length;
98-
for (int i = 0; i < count; i++) {
99-
boolean isHttpAnnotation = false;
100-
if (parameterAnnotations[i] != null) {
101-
isHttpAnnotation = processAnnotationsOnParameter(data, parameterAnnotations[i], i);
102-
}
103-
if (parameterTypes[i] == URI.class) {
104-
data.urlIndex(i);
105-
} else if (!isHttpAnnotation) {
106-
Util.checkState(
107-
data.formParams().isEmpty(), "Body parameters cannot be used with form parameters.");
108-
Util.checkState(data.bodyIndex() == null, "Method has too many Body parameters: %s", method);
109-
data.bodyIndex(i);
110-
data.bodyType(Types.resolve(targetType, targetType, method.getGenericParameterTypes()[i]));
111-
}
112-
}
113-
114-
if (data.headerMapIndex() != null) {
115-
Util.checkState(
116-
Map.class.isAssignableFrom(parameterTypes[data.headerMapIndex()]),
117-
"HeaderMap parameter must be a Map: %s",
118-
parameterTypes[data.headerMapIndex()]);
119-
}
120-
121-
if (data.queryMapIndex() != null) {
122-
Util.checkState(
123-
Map.class.isAssignableFrom(parameterTypes[data.queryMapIndex()]),
124-
"QueryMap parameter must be a Map: %s",
125-
parameterTypes[data.queryMapIndex()]);
126-
}
127-
128-
return data;
129-
}
130-
131-
/**
132-
* Called by parseAndValidateMetadata twice, first on the declaring class, then on the
133-
* target type (unless they are the same).
134-
*
135-
* @param data metadata collected so far relating to the current java method.
136-
* @param clz the class to process
137-
*/
138-
abstract void processAnnotationOnClass(MethodMetadata data, Class<?> clz);
139-
140-
/**
141-
* @param data metadata collected so far relating to the current java method.
142-
* @param annotation annotations present on the current method annotation.
143-
* @param method method currently being processed.
144-
*/
145-
abstract void processAnnotationOnMethod(MethodMetadata data, Annotation annotation, Method method);
146-
147-
/**
148-
* @param data metadata collected so far relating to the current java method.
149-
* @param annotations annotations present on the current parameter annotation.
150-
* @param paramIndex if you find a name in {@code annotations}, call {@link
151-
* #nameParam(MethodMetadata, String, int)} with this as the last parameter.
152-
* @return true if you called {@link #nameParam(MethodMetadata, String, int)} after finding an
153-
* http-relevant annotation.
154-
*/
155-
abstract boolean processAnnotationsOnParameter(MethodMetadata data, Annotation[] annotations, int paramIndex);
156-
157-
@SuppressWarnings("ParameterAssignment")
158-
Collection<String> addTemplatedParam(Collection<String> possiblyNull, String name) {
159-
if (possiblyNull == null) {
160-
possiblyNull = new ArrayList<String>();
161-
}
162-
possiblyNull.add(String.format("{%s}", name));
163-
return possiblyNull;
164-
}
165-
166-
/**
167-
* links a parameter name to its index in the method signature.
168-
*/
169-
void nameParam(MethodMetadata data, String name, int index) {
170-
Collection<String> names =
171-
data.indexToName().containsKey(index) ? data.indexToName().get(index) : new ArrayList<String>();
172-
names.add(name);
173-
data.indexToName().put(index, names);
174-
}
175-
}
17632
}

conjure-java-jaxrs-client/src/main/java/com/palantir/conjure/java/client/jaxrs/CompatibleJaxRsContract.java renamed to conjure-java-jaxrs-client/src/main/java/com/palantir/conjure/java/client/jaxrs/JaxRsContract.java

Lines changed: 127 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,13 @@
2323
import com.palantir.logsafe.exceptions.SafeIllegalStateException;
2424
import java.lang.annotation.Annotation;
2525
import java.lang.reflect.Method;
26+
import java.lang.reflect.Modifier;
27+
import java.net.URI;
28+
import java.util.ArrayList;
2629
import java.util.Collection;
30+
import java.util.LinkedHashMap;
31+
import java.util.List;
32+
import java.util.Map;
2733
import javax.annotation.Nullable;
2834

2935
/**
@@ -32,10 +38,93 @@
3238
* JAXRSContract.java</a> which is licensed under Apache 2.
3339
* We have modified the implementation to handle both jaxrs and jakarta annotations, easing migrations.
3440
*/
35-
final class CompatibleJaxRsContract extends Contract.BaseContract {
41+
final class JaxRsContract implements Contract {
3642

3743
@Override
38-
void processAnnotationOnClass(MethodMetadata data, Class<?> clz) {
44+
public List<MethodMetadata> parseAndValidateMetadata(Class<?> targetType) {
45+
Util.checkState(
46+
targetType.getTypeParameters().length == 0,
47+
"Parameterized types unsupported: %s",
48+
targetType.getSimpleName());
49+
Util.checkState(
50+
targetType.getInterfaces().length <= 1,
51+
"Only single inheritance supported: %s",
52+
targetType.getSimpleName());
53+
if (targetType.getInterfaces().length == 1) {
54+
Util.checkState(
55+
targetType.getInterfaces()[0].getInterfaces().length == 0,
56+
"Only single-level inheritance supported: %s",
57+
targetType.getSimpleName());
58+
}
59+
Map<String, MethodMetadata> result = new LinkedHashMap<String, MethodMetadata>();
60+
for (Method method : targetType.getMethods()) {
61+
if (method.getDeclaringClass() == Object.class
62+
|| (method.getModifiers() & Modifier.STATIC) != 0
63+
|| method.isDefault()) {
64+
continue;
65+
}
66+
MethodMetadata metadata = parseAndValidateMetadata(targetType, method);
67+
Util.checkState(
68+
!result.containsKey(metadata.configKey()), "Overrides unsupported: %s", metadata.configKey());
69+
result.put(metadata.configKey(), metadata);
70+
}
71+
return new ArrayList<MethodMetadata>(result.values());
72+
}
73+
74+
private MethodMetadata parseAndValidateMetadata(Class<?> targetType, Method method) {
75+
MethodMetadata data = new MethodMetadata();
76+
data.returnType(Types.resolve(targetType, targetType, method.getGenericReturnType()));
77+
data.configKey(Feign.configKey(targetType, method));
78+
79+
if (targetType.getInterfaces().length == 1) {
80+
processAnnotationOnClass(data, targetType.getInterfaces()[0]);
81+
}
82+
processAnnotationOnClass(data, targetType);
83+
84+
for (Annotation methodAnnotation : method.getAnnotations()) {
85+
processAnnotationOnMethod(data, methodAnnotation, method);
86+
}
87+
Util.checkState(
88+
data.template().method() != null,
89+
"Method %s not annotated with HTTP method type (ex. GET, POST)",
90+
method.getName());
91+
Class<?>[] parameterTypes = method.getParameterTypes();
92+
93+
Annotation[][] parameterAnnotations = method.getParameterAnnotations();
94+
int count = parameterAnnotations.length;
95+
for (int i = 0; i < count; i++) {
96+
boolean isHttpAnnotation = false;
97+
if (parameterAnnotations[i] != null) {
98+
isHttpAnnotation = processAnnotationsOnParameter(data, parameterAnnotations[i], i);
99+
}
100+
if (parameterTypes[i] == URI.class) {
101+
data.urlIndex(i);
102+
} else if (!isHttpAnnotation) {
103+
Util.checkState(data.formParams().isEmpty(), "Body parameters cannot be used with form parameters.");
104+
Util.checkState(data.bodyIndex() == null, "Method has too many Body parameters: %s", method);
105+
data.bodyIndex(i);
106+
data.bodyType(Types.resolve(targetType, targetType, method.getGenericParameterTypes()[i]));
107+
}
108+
}
109+
110+
if (data.headerMapIndex() != null) {
111+
Util.checkState(
112+
Map.class.isAssignableFrom(parameterTypes[data.headerMapIndex()]),
113+
"HeaderMap parameter must be a Map: %s",
114+
parameterTypes[data.headerMapIndex()]);
115+
}
116+
117+
if (data.queryMapIndex() != null) {
118+
Util.checkState(
119+
Map.class.isAssignableFrom(parameterTypes[data.queryMapIndex()]),
120+
"QueryMap parameter must be a Map: %s",
121+
parameterTypes[data.queryMapIndex()]);
122+
}
123+
124+
return data;
125+
}
126+
127+
private void processAnnotationOnClass(MethodMetadata data, Class<?> clz) {
39128
Annotation path = Annotations.PATH.getAnnotation(clz);
40129
if (path != null) {
41130
String pathValue = Strings.emptyToNull(getAnnotationValue(path));
@@ -60,8 +149,7 @@ void processAnnotationOnClass(MethodMetadata data, Class<?> clz) {
60149
}
61150
}
62151

63-
@Override
64-
void processAnnotationOnMethod(MethodMetadata data, Annotation methodAnnotation, Method method) {
152+
private void processAnnotationOnMethod(MethodMetadata data, Annotation methodAnnotation, Method method) {
65153
Class<? extends Annotation> annotationType = methodAnnotation.annotationType();
66154
Annotation http = Annotations.HTTP_METHOD.getAnnotation(annotationType);
67155
if (http != null) {
@@ -91,26 +179,7 @@ void processAnnotationOnMethod(MethodMetadata data, Annotation methodAnnotation,
91179
}
92180
}
93181

94-
private void handleProducesAnnotation(MethodMetadata data, Annotation produces, String name) {
95-
String[] serverProduces = getAnnotationValues(produces);
96-
String clientAccepts =
97-
serverProduces == null || serverProduces.length == 0 ? null : Strings.emptyToNull(serverProduces[0]);
98-
Preconditions.checkState(clientAccepts != null, "Produces.value() was empty", SafeArg.of("target", name));
99-
data.template().header(HttpHeaders.ACCEPT, (String) null); // remove any previous produces
100-
data.template().header(HttpHeaders.ACCEPT, clientAccepts);
101-
}
102-
103-
private void handleConsumesAnnotation(MethodMetadata data, Annotation consumes, String name) {
104-
String[] serverConsumes = getAnnotationValues(consumes);
105-
String clientProduces =
106-
serverConsumes == null || serverConsumes.length == 0 ? null : Strings.emptyToNull(serverConsumes[0]);
107-
Preconditions.checkState(clientProduces != null, "Consumes.value() was empty", SafeArg.of("target", name));
108-
data.template().header(HttpHeaders.CONTENT_TYPE, (String) null); // remove any previous consumes
109-
data.template().header(HttpHeaders.CONTENT_TYPE, clientProduces);
110-
}
111-
112-
@Override
113-
boolean processAnnotationsOnParameter(MethodMetadata data, Annotation[] annotations, int paramIndex) {
182+
private boolean processAnnotationsOnParameter(MethodMetadata data, Annotation[] annotations, int paramIndex) {
114183
boolean isHttpParam = false;
115184
for (Annotation parameterAnnotation : annotations) {
116185
Class<? extends Annotation> annotationType =
@@ -159,6 +228,40 @@ boolean processAnnotationsOnParameter(MethodMetadata data, Annotation[] annotati
159228
return isHttpParam;
160229
}
161230

231+
private void handleProducesAnnotation(MethodMetadata data, Annotation produces, String name) {
232+
String[] serverProduces = getAnnotationValues(produces);
233+
String clientAccepts =
234+
serverProduces == null || serverProduces.length == 0 ? null : Strings.emptyToNull(serverProduces[0]);
235+
Preconditions.checkState(clientAccepts != null, "Produces.value() was empty", SafeArg.of("target", name));
236+
data.template().header(HttpHeaders.ACCEPT, (String) null); // remove any previous produces
237+
data.template().header(HttpHeaders.ACCEPT, clientAccepts);
238+
}
239+
240+
private void handleConsumesAnnotation(MethodMetadata data, Annotation consumes, String name) {
241+
String[] serverConsumes = getAnnotationValues(consumes);
242+
String clientProduces =
243+
serverConsumes == null || serverConsumes.length == 0 ? null : Strings.emptyToNull(serverConsumes[0]);
244+
Preconditions.checkState(clientProduces != null, "Consumes.value() was empty", SafeArg.of("target", name));
245+
data.template().header(HttpHeaders.CONTENT_TYPE, (String) null); // remove any previous consumes
246+
data.template().header(HttpHeaders.CONTENT_TYPE, clientProduces);
247+
}
248+
249+
@SuppressWarnings("ParameterAssignment")
250+
private static Collection<String> addTemplatedParam(Collection<String> possiblyNull, String name) {
251+
if (possiblyNull == null) {
252+
possiblyNull = new ArrayList<String>();
253+
}
254+
possiblyNull.add(String.format("{%s}", name));
255+
return possiblyNull;
256+
}
257+
258+
private static void nameParam(MethodMetadata data, String name, int index) {
259+
Collection<String> names =
260+
data.indexToName().containsKey(index) ? data.indexToName().get(index) : new ArrayList<String>();
261+
names.add(name);
262+
data.indexToName().put(index, names);
263+
}
264+
162265
@Nullable
163266
private static String getAnnotationValue(Annotation annotation) {
164267
return (String) getAnnotationValueInternal(annotation);

0 commit comments

Comments
 (0)