Skip to content

Commit bfc0158

Browse files
author
Gerald Unterrainer
committed
Merge branch 'develop'
2 parents 5e33aaa + 8db820c commit bfc0158

File tree

5 files changed

+127
-9
lines changed

5 files changed

+127
-9
lines changed

pom.xml

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

1111
<modelVersion>4.0.0</modelVersion>
1212
<artifactId>rest-client</artifactId>
13-
<version>0.0.3</version>
13+
<version>0.0.4</version>
1414
<name>RestClient</name>
1515
<packaging>jar</packaging>
1616

src/main/java/info/unterrainer/commons/restclient/BaseBuilder.java

Lines changed: 121 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
11
package info.unterrainer.commons.restclient;
22

3+
import java.io.UnsupportedEncodingException;
4+
import java.net.URLEncoder;
5+
import java.util.ArrayList;
36
import java.util.HashMap;
7+
import java.util.List;
48
import java.util.Map;
9+
import java.util.stream.Collectors;
10+
11+
import org.mapstruct.ap.internal.util.Strings;
512

613
import com.fasterxml.jackson.core.type.TypeReference;
714
import com.fasterxml.jackson.databind.JavaType;
@@ -10,7 +17,9 @@
1017
import info.unterrainer.commons.restclient.RestClient.HttpGetCall;
1118
import lombok.AccessLevel;
1219
import lombok.RequiredArgsConstructor;
20+
import lombok.extern.slf4j.Slf4j;
1321

22+
@Slf4j
1423
@RequiredArgsConstructor(access = AccessLevel.PACKAGE)
1524
public abstract class BaseBuilder<T, R extends BaseBuilder<T, R>> {
1625

@@ -23,36 +32,121 @@ protected enum Retry {
2332
protected final RestClient client;
2433
protected final Class<?> type;
2534

26-
protected String url;
35+
protected List<String> url = new ArrayList<>();
2736
protected JavaType javaType;
2837
protected TypeReference<?> typeReference;
2938
protected Map<String, String> headers = new HashMap<>();
39+
protected Map<String, String> parameters = new HashMap<>();
3040
protected Retry retry = Retry.ONCE;
3141

42+
/**
43+
* Add a string to an URL.
44+
* <p>
45+
* The URL will be composed of all the parts you add.<br>
46+
* The parts will be checked for trailing and leading slashes, which will be
47+
* removed before adding the URL-part (separated by slashes).<br>
48+
* Null values are ignored. So to add an empty URL-part that should result in
49+
* something like this: 'here/we//go' (between here and go), just add an empty
50+
* string.
51+
*
52+
* @param urlPart the part of the URL to add
53+
* @return a {@link BaseBuilder} to provide a fluent interface.
54+
*/
3255
@SuppressWarnings("unchecked")
33-
public R url(final String url) {
34-
this.url = url;
56+
public R addUrl(final String urlPart) {
57+
if (urlPart != null)
58+
url.add(urlPart);
3559
return (R) this;
3660
}
3761

62+
/**
63+
* Sets the return-type to be of {@link ListJson} with the generic type you
64+
* provided when starting this builder.
65+
*
66+
* @return a {@link BaseBuilder} to provide a fluent interface.
67+
*/
3868
@SuppressWarnings("unchecked")
3969
public R isListJson() {
4070
javaType = client.jsonMapper.getTypeFactory().constructParametricType(ListJson.class, type);
4171
return (R) this;
4272
}
4373

74+
/**
75+
* Adds a header to the call.
76+
* <p>
77+
* All the headers are saved to a map and added later on, when you make the
78+
* call.<br>
79+
* Input containing null as key or value will be ignored.
80+
*
81+
* @param key the key of the header-field to add
82+
* @param value the value of the header-field to add
83+
* @return a {@link BaseBuilder} to provide a fluent interface.
84+
*/
4485
@SuppressWarnings("unchecked")
4586
public R addHeader(final String key, final String value) {
46-
headers.put(key, value);
87+
if (key != null && value != null)
88+
headers.put(key, value);
89+
return (R) this;
90+
}
91+
92+
/**
93+
* Add a query-parameter to the call.
94+
* <p>
95+
* All the parameters are saved in a map and added later on, when you make the
96+
* call.<br>
97+
* The parameters will be checked for trailing and leading '&' and '?', which
98+
* will be removed before adding it to the map.<br>
99+
* Input containing null as key or value will be ignored.
100+
*
101+
* @param key the key of the parameter to add
102+
* @param value the value of the parameter to add
103+
* @return a {@link BaseBuilder} to provide a fluent interface.
104+
*/
105+
@SuppressWarnings("unchecked")
106+
public R addParam(final String key, final String value) {
107+
if (key != null && value != null) {
108+
String k = cutLeadingTrailing("&", key);
109+
k = cutLeadingTrailing("?", k);
110+
try {
111+
k = URLEncoder.encode(k, "UTF-8");
112+
} catch (UnsupportedEncodingException e) {
113+
log.error(String.format("The given key-value %s could not be URL-encoded.", k), e);
114+
}
115+
116+
String v = cutLeadingTrailing("&", value);
117+
v = cutLeadingTrailing("?", v);
118+
try {
119+
v = URLEncoder.encode(v, "UTF-8");
120+
} catch (UnsupportedEncodingException e) {
121+
log.error(String.format("The given parameter-value %s could not be URL-encoded.", v), e);
122+
}
123+
parameters.put(k, v);
124+
}
47125
return (R) this;
48126
}
49127

128+
/**
129+
* By specifying this, you tell the client to retry this call for some time, if
130+
* it fails (see {@link RestClient#retryShort(HttpGetCall)}).
131+
* <p>
132+
* The default is to just try it once and then give up and return an error.
133+
*
134+
* @return a {@link BaseBuilder} to provide a fluent interface.
135+
*/
50136
@SuppressWarnings("unchecked")
51137
public R retryShort() {
52138
retry = Retry.SHORT;
53139
return (R) this;
54140
}
55141

142+
/**
143+
* By specifying this, you tell the client to retry this call for quite some
144+
* time, if it fails (see {@link RestClient#retryEnduring(HttpGetCall)}).
145+
* <p>
146+
* The default is to just try it once and then give up and return an error.
147+
*
148+
* @return a {@link BaseBuilder} to provide a fluent interface.
149+
*/
56150
@SuppressWarnings("unchecked")
57151
public R retryEnduring() {
58152
retry = Retry.ENDURING;
@@ -63,7 +157,21 @@ public R retryEnduring() {
63157

64158
protected abstract HttpGetCall<T> provideJavaTypeCall(String url, JavaType javaType, Map<String, String> headers);
65159

160+
/**
161+
* Execute the call.
162+
*
163+
* @return the return value of type you specified when you created this builder.
164+
*/
66165
public T execute() {
166+
String url = Strings.join(this.url.stream().map(e -> cutLeadingTrailing("/", e)).collect(Collectors.toList()),
167+
"/");
168+
169+
String params = Strings.join(
170+
parameters.entrySet().stream().map(e -> e.getKey() + "=" + e.getValue()).collect(Collectors.toList()),
171+
"&");
172+
if (!params.isBlank())
173+
url += "?" + params;
174+
67175
switch (retry) {
68176
case SHORT:
69177
return client.retryShort(provide(url, type, javaType, headers));
@@ -81,4 +189,13 @@ private HttpGetCall<T> provide(final String url, final Class<?> type, final Java
81189
return provideJavaTypeCall(url, javaType, headers);
82190
return provideCall(url, (Class<T>) type, headers);
83191
}
192+
193+
private String cutLeadingTrailing(final String s, final String input) {
194+
String u = input;
195+
while (u.startsWith(s))
196+
u = u.substring(1);
197+
while (u.endsWith(s))
198+
u = u.substring(0, u.length() - 2);
199+
return u;
200+
}
84201
}

src/main/java/info/unterrainer/commons/restclient/KeycloakContext.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ void update(final RestClient client) {
7575
response = client.<TokenResponseJson>post(TokenResponseJson.class)
7676
.addHeader("Content-Type", "application/x-www-form-urlencoded")
7777
.addHeader("Accept", "application/json")
78-
.url(keycloakUrl)
78+
.addUrl(keycloakUrl)
7979
.retryShort()
8080
.mediaType("application/x-www-form-urlencoded")
8181
.body(body)

src/test/java/info/unterrainer/commons/restclient/BuilderTests.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ public void BeforeAll() {
2020
@Test
2121
public void correctCredentialsConnect() {
2222
String response = restClient.<String>get(String.class)
23-
.url("https://elite-server.lan.elite-zettl.at/")
23+
.addUrl("https://elite-server.lan.elite-zettl.at/")
2424
.execute();
2525

2626
System.out.println(response);
@@ -29,7 +29,7 @@ public void correctCredentialsConnect() {
2929
@Test
3030
public void jsonDeserializationWorks() {
3131
MessageJson response = restClient.<MessageJson>get(MessageJson.class)
32-
.url("https://elite-server.lan.elite-zettl.at/")
32+
.addUrl("https://elite-server.lan.elite-zettl.at/")
3333
.execute();
3434

3535
System.out.println(response);

src/test/java/info/unterrainer/commons/restclient/KeycloakContextTests.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ public void BeforeAll() {
2525
public void listJsonDeserializationWorks() {
2626
ListJson<EliteUserJson> users = kcc.<ListJson<EliteUserJson>>get(restClient, EliteUserJson.class)
2727
.isListJson()
28-
.url("https://elite-server.lan.elite-zettl.at/users")
28+
.addUrl("https://elite-server.lan.elite-zettl.at")
29+
.addUrl("users")
2930
.execute();
3031

3132
System.out.println(users);

0 commit comments

Comments
 (0)