Skip to content

Commit 008fac3

Browse files
authored
Merge pull request #166 from gocardless/template-changes
Changes from gocardless/client-library-templates
2 parents c7ca28d + 319d0b6 commit 008fac3

23 files changed

Lines changed: 705 additions & 172 deletions

MIGRATION_V3.md

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
# Upgrading from v2.x to v3.x or above
2+
3+
To upgrade from v2.x, you will need to switch from calling `GoCardlessClient.create` with arguments to
4+
using the `Builder` returned by `GoCardlessClient.newBuilder()` and its `withX()` and `build()` methods.
5+
6+
If you're only setting an access token and using the default GoCardless environment (live):
7+
8+
```java
9+
import com.gocardless.GoCardlessClient;
10+
11+
String accessToken = "foo";
12+
13+
// Before
14+
GoCardlessClient client = GoCardlessClient.create(accessToken)
15+
16+
// After
17+
GoCardlessClient client = GoCardlessClient.newBuilder(accessToken).build();
18+
```
19+
20+
If you're customising the environment as well:
21+
22+
```java
23+
import com.gocardless.GoCardlessClient;
24+
25+
String accessToken = "foo";
26+
27+
// Before
28+
GoCardlessClient client = GoCardlessClient.create(accessToken, GoCardlessClient.Environment.SANDBOX)
29+
30+
// After
31+
GoCardlessClient client = GoCardlessClient.newBuilder(accessToken)
32+
.withEnvironment(GoCardlessClient.Environment.SANDBOX)
33+
.build();
34+
```
35+
36+
Or, if you're customising the base URL:
37+
38+
```java
39+
import com.gocardless.GoCardlessClient;
40+
41+
String accessToken = "foo";
42+
String baseUrl = "https://api.gocardless.com";
43+
44+
// Before
45+
GoCardlessClient client = GoCardlessClient.create(accessToken, baseUrl)
46+
47+
// After
48+
GoCardlessClient client = GoCardlessClient.newBuilder(accessToken)
49+
.withBaseUrl(baseUrl)
50+
.build();
51+
```
52+
53+
If you were instantiating your own `com.gocardless.http.HttpClient` (which is very unlikely unless you
54+
were patching the internals of the library), you'll now need to supply an `OkHttpClient` as well as the
55+
access token and base URL.
56+
57+
```java
58+
String accessToken = "foo";
59+
String baseUrl = "https://api.gocardless.com";
60+
61+
// Before
62+
HttpClient rawClient = new HttpClient(accessToken, baseUrl);
63+
64+
// After
65+
HttpClient rawClient = new HttpClient(accessToken, baseUrl, new OkHttpClient());
66+
```
67+
68+
Once you've instantiated the client, everything works exactly the same as before, so you won't need to
69+
change any of your other code.

MIGRATION_V5.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# Upgrading from v4.x or earlier to v5.x or above
2+
3+
## Breaking Changes
4+
5+
- Stop support for apps using Java 7, supports apps using only Java 8 and above
6+
- Response Header names are all in lower case now
7+
- GoCardless client initiation method `withsslSocketFactory` replaced with `withSslSocketFactoryAndTrustManager`
8+
9+
```java
10+
import com.gocardless.GoCardlessClient;
11+
import javax.net.ssl.SSLSocketFactory;
12+
import javax.net.ssl.TrustManager;
13+
import javax.net.ssl.TrustManagerFactory;
14+
import javax.net.ssl.X509TrustManager;
15+
import java.security.KeyStore;
16+
17+
String accessToken = "AO00000123";
18+
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(
19+
TrustManagerFactory.getDefaultAlgorithm());
20+
trustManagerFactory.init((KeyStore) null);
21+
TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
22+
if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {
23+
throw new IllegalStateException("Unexpected default trust managers:"
24+
+ Arrays.toString(trustManagers));
25+
}
26+
X509TrustManager trustManager = (X509TrustManager) trustManagers[0];
27+
28+
SSLContext sslContext = SSLContext.getInstance("TLS");
29+
sslContext.init(null, new TrustManager[] { trustManager }, null);
30+
SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
31+
32+
33+
GoCardlessClient client = GoCardlessClient.newBuilder(accessToken)
34+
.withSslSocketFactoryAndTrustManager(sslSocketFactory, trustManager)
35+
.build();
36+
```

MIGRATION_V8.md

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
# Migration Guide from v7 or earlier to v8
2+
3+
## Breaking Changes
4+
5+
### Metadata values must be strings
6+
7+
**Why**: The GoCardless API only accepts string values for metadata, but the Java types previously allowed `Map<String, Object>`. This caused confusing runtime errors. The new version fixes the types to match the API requirements.
8+
9+
**Impact**: Code that passes non-string values to `metadata` fields will fail to compile.
10+
11+
---
12+
13+
## Quick Migration
14+
15+
### Option 1: Use MetadataHelper (Recommended) ✅
16+
17+
The easiest way to migrate is using the new `MetadataHelper` class:
18+
19+
```java
20+
import com.gocardless.helpers.MetadataHelper;
21+
import java.util.HashMap;
22+
import java.util.Map;
23+
24+
// ❌ BEFORE - Compiled but failed at runtime
25+
Map<String, Object> metadata = new HashMap<>();
26+
metadata.put("user_id", 12345); // Integer
27+
metadata.put("is_active", true); // Boolean
28+
metadata.put("tags", Arrays.asList("vip", "premium")); // List
29+
30+
client.customers().create()
31+
.withEmail("user@example.com")
32+
.withMetadata(metadata) // Runtime error!
33+
.execute();
34+
35+
// ✅ AFTER - One function call
36+
client.customers().create()
37+
.withEmail("user@example.com")
38+
.withMetadata(MetadataHelper.toMetadata(metadata)) // Converts all values
39+
.execute();
40+
```
41+
42+
### Option 2: Manual Conversion
43+
44+
If you prefer explicit control:
45+
46+
```java
47+
Map<String, String> metadata = new HashMap<>();
48+
metadata.put("user_id", String.valueOf(12345)); // "12345"
49+
metadata.put("is_active", String.valueOf(true)); // "true"
50+
51+
Gson gson = new Gson();
52+
metadata.put("tags", gson.toJson(Arrays.asList("vip", "premium"))); // JSON
53+
54+
client.customers().create()
55+
.withEmail("user@example.com")
56+
.withMetadata(metadata)
57+
.execute();
58+
```
59+
60+
---
61+
62+
## Helper Functions Reference
63+
64+
### `MetadataHelper.toMetadata(obj)`
65+
66+
Converts a map with mixed value types to metadata format:
67+
68+
```java
69+
Map<String, Object> data = new HashMap<>();
70+
data.put("user_id", 12345);
71+
data.put("is_premium", true);
72+
data.put("signup_date", new Date());
73+
data.put("preferences", Map.of("theme", "dark"));
74+
75+
Map<String, String> metadata = MetadataHelper.toMetadata(data);
76+
// Result: {
77+
// "user_id": "12345",
78+
// "is_premium": "true",
79+
// "signup_date": "Mon Jan 15 10:30:00 GMT 2024",
80+
// "preferences": "{\"theme\":\"dark\"}"
81+
// }
82+
```
83+
84+
### `MetadataHelper.toMetadataValue(value)`
85+
86+
Converts a single value:
87+
88+
```java
89+
MetadataHelper.toMetadataValue(12345); // "12345"
90+
MetadataHelper.toMetadataValue(true); // "true"
91+
MetadataHelper.toMetadataValue(Arrays.asList("vip")); // "[\"vip\"]"
92+
MetadataHelper.toMetadataValue(Map.of("theme", "dark")); // "{\"theme\":\"dark\"}"
93+
```
94+
95+
### `MetadataHelper.isValidMetadata(obj)`
96+
97+
Check if metadata is valid:
98+
99+
```java
100+
Map<String, Object> metadata = new HashMap<>();
101+
metadata.put("key", "value");
102+
103+
if (MetadataHelper.isValidMetadata(metadata)) {
104+
// All values are strings
105+
client.customers().create()
106+
.withMetadata((Map<String, String>) (Object) metadata)
107+
.execute();
108+
}
109+
```
110+
111+
### `MetadataHelper.parseMetadataValue(value, type)`
112+
113+
Parse metadata values back to their original types:
114+
115+
```java
116+
Customer customer = client.customers().get("CU123").execute();
117+
Map<String, String> metadata = customer.getMetadata();
118+
119+
// Parse back to original types
120+
Integer userId = MetadataHelper.parseMetadataValue(
121+
metadata.get("user_id"),
122+
Integer.class
123+
); // 12345
124+
125+
Boolean isActive = MetadataHelper.parseMetadataValue(
126+
metadata.get("is_active"),
127+
Boolean.class
128+
); // true
129+
130+
// For generic types, use TypeToken
131+
List<String> tags = MetadataHelper.parseMetadataValue(
132+
metadata.get("tags"),
133+
new TypeToken<List<String>>(){}.getType()
134+
); // ["vip", "premium"]
135+
```

README.md

Lines changed: 4 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,14 @@ With Maven:
1414
<dependency>
1515
<groupId>com.gocardless</groupId>
1616
<artifactId>gocardless-pro</artifactId>
17-
<version>7.6.0</version>
17+
<version>8.0.0</version>
1818
</dependency>
1919
```
2020

2121
With Gradle:
2222

2323
```
24-
implementation 'com.gocardless:gocardless-pro:7.6.0'
24+
implementation 'com.gocardless:gocardless-pro:8.0.0'
2525
```
2626

2727
## Initializing the client
@@ -228,112 +228,9 @@ public class WebhookHandler {
228228

229229
For more details on working with webhooks, see our ["Getting started" guide](https://developer.gocardless.com/getting-started/api/introduction/?lang=java).
230230

231-
## Upgrading from v4.x to v5.x or above
231+
## Upgrading from older versions
232232

233-
### Breaking Changes
234-
235-
- Stop support for apps using Java 7, supports apps using only Java 8 and above
236-
- Response Header names are all in lower case now
237-
- GoCardless client initiation method `withsslSocketFactory` replaced with `withSslSocketFactoryAndTrustManager`
238-
239-
```java
240-
import com.gocardless.GoCardlessClient;
241-
import javax.net.ssl.SSLSocketFactory;
242-
import javax.net.ssl.TrustManager;
243-
import javax.net.ssl.TrustManagerFactory;
244-
import javax.net.ssl.X509TrustManager;
245-
import java.security.KeyStore;
246-
247-
String accessToken = "AO00000123";
248-
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(
249-
TrustManagerFactory.getDefaultAlgorithm());
250-
trustManagerFactory.init((KeyStore) null);
251-
TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
252-
if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {
253-
throw new IllegalStateException("Unexpected default trust managers:"
254-
+ Arrays.toString(trustManagers));
255-
}
256-
X509TrustManager trustManager = (X509TrustManager) trustManagers[0];
257-
258-
SSLContext sslContext = SSLContext.getInstance("TLS");
259-
sslContext.init(null, new TrustManager[] { trustManager }, null);
260-
SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
261-
262-
263-
GoCardlessClient client = GoCardlessClient.newBuilder(accessToken)
264-
.withSslSocketFactoryAndTrustManager(sslSocketFactory, trustManager)
265-
.build();
266-
```
267-
268-
## Upgrading from v2.x to v3.x or above
269-
270-
To upgrade from v2.x, you will need to switch from calling `GoCardlessClient.create` with arguments to
271-
using the `Builder` returned by `GoCardlessClient.newBuilder()` and its `withX()` and `build()` methods.
272-
273-
If you're only setting an access token and using the default GoCardless environment (live):
274-
275-
```java
276-
import com.gocardless.GoCardlessClient;
277-
278-
String accessToken = "foo";
279-
280-
// Before
281-
GoCardlessClient client = GoCardlessClient.create(accessToken)
282-
283-
// After
284-
GoCardlessClient client = GoCardlessClient.newBuilder(accessToken).build();
285-
```
286-
287-
If you're customising the environment as well:
288-
289-
```java
290-
import com.gocardless.GoCardlessClient;
291-
292-
String accessToken = "foo";
293-
294-
// Before
295-
GoCardlessClient client = GoCardlessClient.create(accessToken, GoCardlessClient.Environment.SANDBOX)
296-
297-
// After
298-
GoCardlessClient client = GoCardlessClient.newBuilder(accessToken)
299-
.withEnvironment(GoCardlessClient.Environment.SANDBOX)
300-
.build();
301-
```
302-
303-
Or, if you're customising the base URL:
304-
305-
```java
306-
import com.gocardless.GoCardlessClient;
307-
308-
String accessToken = "foo";
309-
String baseUrl = "https://api.gocardless.com";
310-
311-
// Before
312-
GoCardlessClient client = GoCardlessClient.create(accessToken, baseUrl)
313-
314-
// After
315-
GoCardlessClient client = GoCardlessClient.newBuilder(accessToken)
316-
.withBaseUrl(baseUrl)
317-
.build();
318-
```
319-
320-
If you were instantiating your own `com.gocardless.http.HttpClient` (which is very unlikely unless you
321-
were patching the internals of the library), you'll now need to supply an `OkHttpClient` as well as the
322-
access token and base URL.
323-
324-
```java
325-
String accessToken = "foo";
326-
String baseUrl = "https://api.gocardless.com";
327-
328-
// Before
329-
HttpClient rawClient = new HttpClient(accessToken, baseUrl);
330-
331-
// After
332-
HttpClient rawClient = new HttpClient(accessToken, baseUrl, new OkHttpClient());
333-
```
334-
335-
Once you've instantiated the client, everything works exactly the same as before, so you won't need to
336-
change any of your other code.
233+
If you're upgrading from v7 or earlier to v8 or later, see: MIGRATION_V8.md
337234

338235
## Compatibility
339236

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ plugins {
2929
sourceCompatibility = 1.8
3030
targetCompatibility = 1.8
3131
group = 'com.gocardless'
32-
version = '7.6.0'
32+
version = '8.0.0'
3333

3434
apply plugin: 'ch.raffael.pegdown-doclet'
3535

0 commit comments

Comments
 (0)