Skip to content

Commit 5fc6e37

Browse files
authored
Merge pull request #3 from sashirestela/developer
Support for Generic sender and Default methods
2 parents 7346616 + 289fda5 commit 5fc6e37

19 files changed

+267
-70
lines changed

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
<groupId>io.github.sashirestela</groupId>
88
<artifactId>cleverclient</artifactId>
9-
<version>0.2.0</version>
9+
<version>0.3.0</version>
1010
<packaging>jar</packaging>
1111

1212
<name>cleverclient</name>

src/main/java/io/github/sashirestela/cleverclient/CleverClient.java

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,34 +2,36 @@
22

33
import java.net.http.HttpClient;
44
import java.util.List;
5+
import java.util.Optional;
56

67
import org.slf4j.Logger;
78
import org.slf4j.LoggerFactory;
89

910
import io.github.sashirestela.cleverclient.http.HttpProcessor;
1011
import io.github.sashirestela.cleverclient.http.InvocationFilter;
1112
import lombok.Builder;
13+
import lombok.Getter;
1214
import lombok.NoArgsConstructor;
1315
import lombok.NonNull;
1416

1517
@NoArgsConstructor
18+
@Getter
1619
public class CleverClient {
1720
private static Logger logger = LoggerFactory.getLogger(CleverClient.class);
1821

19-
@NonNull
20-
private HttpClient httpClient;
21-
2222
@NonNull
2323
private String urlBase;
2424

2525
private List<String> headers;
26+
private HttpClient httpClient;
27+
2628
private HttpProcessor httpProcessor;
2729

2830
@Builder
29-
public CleverClient(HttpClient httpClient, String urlBase, List<String> headers) {
30-
this.httpClient = httpClient;
31+
public CleverClient(String urlBase, List<String> headers, HttpClient httpClient) {
3132
this.urlBase = urlBase;
32-
this.headers = headers;
33+
this.headers = Optional.ofNullable(headers).orElse(List.of());
34+
this.httpClient = Optional.ofNullable(httpClient).orElse(HttpClient.newHttpClient());
3335
this.httpProcessor = new HttpProcessor(this.httpClient, this.urlBase, this.headers);
3436
logger.debug("CleverClient has been created.");
3537
}

src/main/java/io/github/sashirestela/cleverclient/http/HttpConnector.java

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,25 @@ public class HttpConnector {
3131
public Object sendRequest() {
3232
var bodyPublisher = createBodyPublisher(bodyObject, isMultipart);
3333
var responseClass = returnType.getBaseClass();
34-
var httpRequest = HttpRequest.newBuilder()
35-
.uri(URI.create(url))
36-
.headers(headersArray)
37-
.method(httpMethod, bodyPublisher)
38-
.build();
34+
HttpRequest httpRequest = null;
35+
if (headersArray.length > 0) {
36+
httpRequest = HttpRequest.newBuilder()
37+
.uri(URI.create(url))
38+
.headers(headersArray)
39+
.method(httpMethod, bodyPublisher)
40+
.build();
41+
} else {
42+
httpRequest = HttpRequest.newBuilder()
43+
.uri(URI.create(url))
44+
.method(httpMethod, bodyPublisher)
45+
.build();
46+
}
3947
var httpSender = HttpSenderFactory.get().createSender(returnType);
40-
return httpSender.sendRequest(httpClient, httpRequest, responseClass);
48+
if (returnType.isGeneric()) {
49+
return httpSender.sendRequest(httpClient, httpRequest, responseClass, returnType.getGenericClass());
50+
} else {
51+
return httpSender.sendRequest(httpClient, httpRequest, responseClass, null);
52+
}
4153
}
4254

4355
private BodyPublisher createBodyPublisher(Object bodyObject, boolean isMultipart) {

src/main/java/io/github/sashirestela/cleverclient/http/HttpInvocationHandler.java

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package io.github.sashirestela.cleverclient.http;
22

3+
import java.lang.invoke.MethodHandles;
4+
import java.lang.invoke.MethodType;
35
import java.lang.reflect.InvocationHandler;
46
import java.lang.reflect.Method;
57

@@ -24,9 +26,21 @@ public Object invoke(Object proxy, Method method, Object[] arguments) throws Thr
2426
filter.apply(method, arguments);
2527
logger.debug("Applied Filter : {}", filter.getClass().getSimpleName());
2628
}
27-
var responseObject = processor.resolve(method, arguments);
28-
logger.debug("Received Response");
29-
30-
return responseObject;
29+
if (method.isDefault()) {
30+
return MethodHandles.lookup()
31+
.findSpecial(
32+
method.getDeclaringClass(),
33+
method.getName(),
34+
MethodType.methodType(
35+
method.getReturnType(),
36+
method.getParameterTypes()),
37+
method.getDeclaringClass())
38+
.bindTo(proxy)
39+
.invokeWithArguments(arguments);
40+
} else {
41+
var responseObject = processor.resolve(method, arguments);
42+
logger.debug("Received Response");
43+
return responseObject;
44+
}
3145
}
3246
}

src/main/java/io/github/sashirestela/cleverclient/http/HttpProcessor.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ public class HttpProcessor {
3030
public HttpProcessor(HttpClient httpClient, String urlBase, List<String> headers) {
3131
this.httpClient = httpClient;
3232
this.urlBase = urlBase;
33-
this.headers = headers;
33+
this.headers = Optional.ofNullable(headers).orElse(List.of());
3434
}
3535

3636
/**

src/main/java/io/github/sashirestela/cleverclient/http/ReturnType.java

Lines changed: 62 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,23 @@ public class ReturnType {
88
private static final String LIST = "java.util.List";
99
private static final String STRING = "java.lang.String";
1010

11+
private static final String REGEX = "[<>]";
12+
private static final String JAVA_PCK = "java";
13+
1114
private String fullClassName;
1215
private String[] returnTypeArray;
1316
private int size;
17+
private int firstIndex;
1418
private int lastIndex;
1519
private int prevLastIndex;
1620

1721
public ReturnType(String fullClassName) {
1822
this.fullClassName = fullClassName;
19-
returnTypeArray = fullClassName.split("[<>]", 0);
23+
returnTypeArray = fullClassName.split(REGEX, 0);
2024
size = returnTypeArray.length;
25+
firstIndex = 0;
2126
lastIndex = size - 1;
22-
prevLastIndex = size > 1 ? lastIndex - 1 : -1;
27+
prevLastIndex = lastIndex - 1;
2328
}
2429

2530
public ReturnType(Method method) {
@@ -31,53 +36,78 @@ public String getFullClassName() {
3136
}
3237

3338
public Class<?> getBaseClass() {
34-
Class<?> baseClass = null;
39+
return getClass(lastIndex);
40+
}
41+
42+
public Class<?> getGenericClass() {
43+
return getClass(prevLastIndex);
44+
}
45+
46+
private Class<?> getClass(int index) {
47+
Class<?> clazz = null;
3548
try {
36-
baseClass = Class.forName(returnTypeArray[lastIndex]);
49+
clazz = Class.forName(returnTypeArray[index]);
3750
} catch (ClassNotFoundException e) {
3851
// This shouldn't happen
3952
}
40-
return baseClass;
53+
return clazz;
4154
}
4255

4356
public Category category() {
4457
if (isAsync()) {
45-
if (isStream()) {
46-
return Category.ASYNC_STREAM;
47-
} else if (isList()) {
48-
return Category.ASYNC_LIST;
49-
} else if (isObject()) {
50-
return Category.ASYNC_OBJECT;
51-
} else if (isPlainText()) {
52-
return Category.ASYNC_PLAIN_TEXT;
53-
} else {
54-
return null;
55-
}
58+
return asyncCategory();
5659
} else {
57-
if (isStream()) {
58-
return Category.SYNC_STREAM;
59-
} else if (isList()) {
60-
return Category.SYNC_LIST;
61-
} else if (isObject()) {
62-
return Category.SYNC_OBJECT;
63-
} else if (isPlainText()) {
64-
return Category.SYNC_PLAIN_TEXT;
65-
} else {
66-
return null;
67-
}
60+
return syncCategory();
61+
}
62+
}
63+
64+
private Category asyncCategory() {
65+
if (isStream()) {
66+
return Category.ASYNC_STREAM;
67+
} else if (isList()) {
68+
return Category.ASYNC_LIST;
69+
} else if (isGeneric()) {
70+
return Category.ASYNC_GENERIC;
71+
} else if (isObject()) {
72+
return Category.ASYNC_OBJECT;
73+
} else if (isPlainText()) {
74+
return Category.ASYNC_PLAIN_TEXT;
75+
} else {
76+
return null;
77+
}
78+
}
79+
80+
private Category syncCategory() {
81+
if (isStream()) {
82+
return Category.SYNC_STREAM;
83+
} else if (isList()) {
84+
return Category.SYNC_LIST;
85+
} else if (isGeneric()) {
86+
return Category.SYNC_GENERIC;
87+
} else if (isObject()) {
88+
return Category.SYNC_OBJECT;
89+
} else if (isPlainText()) {
90+
return Category.SYNC_PLAIN_TEXT;
91+
} else {
92+
return null;
6893
}
6994
}
7095

7196
public boolean isAsync() {
72-
return size > 1 && ASYNC.equals(returnTypeArray[0]);
97+
return size > 1 && ASYNC.equals(returnTypeArray[firstIndex]);
7398
}
7499

75100
public boolean isStream() {
76-
return size != 1 && STREAM.equals(returnTypeArray[prevLastIndex]);
101+
return size > 1 && STREAM.equals(returnTypeArray[prevLastIndex]);
77102
}
78103

79104
public boolean isList() {
80-
return size != 1 && LIST.equals(returnTypeArray[prevLastIndex]);
105+
return size > 1 && LIST.equals(returnTypeArray[prevLastIndex]);
106+
}
107+
108+
public boolean isGeneric() {
109+
return ((isAsync() && size > 2) || (!isAsync() && size > 1))
110+
&& !returnTypeArray[prevLastIndex].startsWith(JAVA_PCK);
81111
}
82112

83113
public boolean isObject() {
@@ -95,10 +125,12 @@ private boolean isString() {
95125
public enum Category {
96126
ASYNC_STREAM,
97127
ASYNC_LIST,
128+
ASYNC_GENERIC,
98129
ASYNC_OBJECT,
99130
ASYNC_PLAIN_TEXT,
100131
SYNC_STREAM,
101132
SYNC_LIST,
133+
SYNC_GENERIC,
102134
SYNC_OBJECT,
103135
SYNC_PLAIN_TEXT;
104136
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package io.github.sashirestela.cleverclient.sender;
2+
3+
import java.net.http.HttpClient;
4+
import java.net.http.HttpRequest;
5+
import java.net.http.HttpResponse.BodyHandlers;
6+
7+
import io.github.sashirestela.cleverclient.util.JsonUtil;
8+
9+
public class HttpAsyncGenericSender extends HttpSender {
10+
11+
@Override
12+
public <S, T> Object sendRequest(HttpClient httpClient, HttpRequest httpRequest, Class<T> responseClass,
13+
Class<S> genericClass) {
14+
15+
var httpResponseFuture = httpClient.sendAsync(httpRequest, BodyHandlers.ofString());
16+
17+
return httpResponseFuture.thenApply(response -> {
18+
19+
throwExceptionIfErrorIsPresent(response, false);
20+
21+
logger.debug("Response : {}", response.body());
22+
23+
return JsonUtil.jsonToParametricObject(response.body(), genericClass, responseClass);
24+
});
25+
}
26+
27+
}

src/main/java/io/github/sashirestela/cleverclient/sender/HttpAsyncListSender.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@
99
public class HttpAsyncListSender extends HttpSender {
1010

1111
@Override
12-
public <T> Object sendRequest(HttpClient httpClient, HttpRequest httpRequest, Class<T> responseClass) {
12+
public <S, T> Object sendRequest(HttpClient httpClient, HttpRequest httpRequest, Class<T> responseClass,
13+
Class<S> genericClass) {
14+
1315
var httpResponseFuture = httpClient.sendAsync(httpRequest, BodyHandlers.ofString());
1416

1517
return httpResponseFuture.thenApply(response -> {

src/main/java/io/github/sashirestela/cleverclient/sender/HttpAsyncObjectSender.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@
99
public class HttpAsyncObjectSender extends HttpSender {
1010

1111
@Override
12-
public <T> Object sendRequest(HttpClient httpClient, HttpRequest httpRequest, Class<T> responseClass) {
12+
public <S, T> Object sendRequest(HttpClient httpClient, HttpRequest httpRequest, Class<T> responseClass,
13+
Class<S> genericClass) {
14+
1315
var httpResponseFuture = httpClient.sendAsync(httpRequest, BodyHandlers.ofString());
1416

1517
return httpResponseFuture.thenApply(response -> {

src/main/java/io/github/sashirestela/cleverclient/sender/HttpAsyncPlainTextSender.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ public class HttpAsyncPlainTextSender extends HttpSender {
88

99
@Override
1010
@SuppressWarnings("unchecked")
11-
public <T> Object sendRequest(HttpClient httpClient, HttpRequest httpRequest, Class<T> responseClass) {
11+
public <S, T> Object sendRequest(HttpClient httpClient, HttpRequest httpRequest, Class<T> responseClass,
12+
Class<S> genericClass) {
13+
1214
var httpResponseFuture = httpClient.sendAsync(httpRequest, BodyHandlers.ofString());
1315

1416
return httpResponseFuture.thenApply(response -> {

0 commit comments

Comments
 (0)