Skip to content

Commit bec2793

Browse files
committed
Move Pb Details parsing into SolidClientException
Parsing Problem Details parsing into the SolidClientExceptions makes it possible to reuse, e.g. in the upcoming BodyHandlers changes.
1 parent 0963f89 commit bec2793

File tree

2 files changed

+68
-49
lines changed

2 files changed

+68
-49
lines changed

solid/src/main/java/com/inrupt/client/solid/SolidClient.java

Lines changed: 3 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,6 @@
2222

2323
import com.inrupt.client.*;
2424
import com.inrupt.client.auth.Session;
25-
import com.inrupt.client.spi.JsonService;
26-
import com.inrupt.client.spi.ServiceProvider;
2725

2826
import java.io.ByteArrayInputStream;
2927
import java.io.IOException;
@@ -54,21 +52,11 @@ public class SolidClient {
5452
private final Client client;
5553
private final Headers defaultHeaders;
5654
private final boolean fetchAfterWrite;
57-
private final JsonService jsonService;
5855

5956
SolidClient(final Client client, final Headers headers, final boolean fetchAfterWrite) {
6057
this.client = Objects.requireNonNull(client, "Client may not be null!");
6158
this.defaultHeaders = Objects.requireNonNull(headers, "Headers may not be null!");
6259
this.fetchAfterWrite = fetchAfterWrite;
63-
JsonService js;
64-
try {
65-
// It is acceptable for a SolidClient instance to be in a classpath without any implementation for
66-
// JsonService, in which case the ProblemDetails exceptions will fallback to default and not be parsed.
67-
js = ServiceProvider.getJsonService();
68-
} catch (IllegalStateException e) {
69-
js = null;
70-
}
71-
this.jsonService = js;
7260
}
7361

7462
/**
@@ -134,7 +122,7 @@ public <T extends Resource> CompletionStage<T> read(final URI identifier, final
134122
return client.send(request, Response.BodyHandlers.ofByteArray())
135123
.thenApply(response -> {
136124
if (response.statusCode() >= ERROR_STATUS) {
137-
throw this.exceptionFromErrorResponse(
125+
throw SolidClientException.fromErrorResponse(
138126
"Unable to read resource at " + request.uri(),
139127
response.uri(),
140128
response.statusCode(),
@@ -289,7 +277,7 @@ public <T extends Resource> CompletionStage<Void> delete(final T resource, final
289277
if (isSuccess(res.statusCode())) {
290278
return null;
291279
} else {
292-
throw this.exceptionFromErrorResponse(
280+
throw SolidClientException.fromErrorResponse(
293281
"Unable to delete resource",
294282
resource.getIdentifier(),
295283
res.statusCode(),
@@ -381,7 +369,7 @@ <T extends Resource> Function<Response<byte[]>, CompletionStage<T>> handleRespon
381369
final Headers headers, final String message) {
382370
return res -> {
383371
if (!isSuccess(res.statusCode())) {
384-
throw this.exceptionFromErrorResponse(
372+
throw SolidClientException.fromErrorResponse(
385373
message,
386374
resource.getIdentifier(),
387375
res.statusCode(),
@@ -472,38 +460,4 @@ static Request.BodyPublisher cast(final Resource resource) {
472460
" into Solid Resource", ex);
473461
}
474462
}
475-
476-
private SolidClientException exceptionFromErrorResponse(
477-
final String message,
478-
final URI uri,
479-
final int code,
480-
final Headers headers,
481-
final byte[] body
482-
) {
483-
ProblemDetails pd;
484-
if (
485-
this.jsonService == null
486-
|| (headers != null && !headers.allValues("Content-Type").contains(ProblemDetails.MIME_TYPE))) {
487-
pd = new ProblemDetails(null, HttpStatus.getStatusMessage(code), null, code, null);
488-
return SolidClientException.handle(message, pd, uri, headers, new String(body));
489-
}
490-
try {
491-
// ProblemDetails doesn't have a default constructor, and we can't use JSON mapping annotations because
492-
// the JSON service is an abstraction over JSON-B and Jackson, so we deserialize the JSON object in a Map
493-
// and build the ProblemDetails from the Map values.
494-
final Map<String, Object> pdData = this.jsonService.fromJson(
495-
new ByteArrayInputStream(body),
496-
new HashMap<String, Object>(){}.getClass().getGenericSuperclass()
497-
);
498-
final String title = (String) pdData.get("title");
499-
final String details = (String) pdData.get("details");
500-
final URI type = URI.create((String) pdData.get("type"));
501-
final URI instance = URI.create((String) pdData.get("instance"));
502-
final int status = (int) pdData.get("status");
503-
pd = new ProblemDetails(type, title, details, status, instance);
504-
} catch (IOException e) {
505-
pd = new ProblemDetails( null, HttpStatus.getStatusMessage(code), null, code, null);
506-
}
507-
return SolidClientException.handle(message, pd, uri, headers, new String(body));
508-
}
509463
}

solid/src/main/java/com/inrupt/client/solid/SolidClientException.java

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,14 @@
2323
import com.inrupt.client.ClientHttpException;
2424
import com.inrupt.client.Headers;
2525
import com.inrupt.client.ProblemDetails;
26+
import com.inrupt.client.spi.JsonService;
27+
import com.inrupt.client.spi.ServiceProvider;
2628

29+
import java.io.ByteArrayInputStream;
30+
import java.io.IOException;
2731
import java.net.URI;
32+
import java.util.HashMap;
33+
import java.util.Map;
2834

2935
/**
3036
* A runtime exception for use with SolidClient HTTP operations.
@@ -37,6 +43,9 @@ public class SolidClientException extends ClientHttpException {
3743
private final int statusCode;
3844
private final String body;
3945
private final transient Headers headers;
46+
private static JsonService jsonService;
47+
private static boolean jsonServiceInitialized = false;
48+
4049

4150
/**
4251
* Create a SolidClient exception.
@@ -107,6 +116,62 @@ public String getBody() {
107116
return body;
108117
}
109118

119+
/**
120+
* It is acceptable for a SolidClient instance to be in a classpath without any implementation for
121+
* JsonService, in which case the ProblemDetails exceptions will fallback to default and not be parsed.
122+
* @return a JsonService instance, null if none is available
123+
*/
124+
private static JsonService getJsonService() {
125+
if (SolidClientException.jsonServiceInitialized) {
126+
return SolidClientException.jsonService;
127+
}
128+
JsonService js;
129+
try {
130+
131+
js = ServiceProvider.getJsonService();
132+
} catch (IllegalStateException e) {
133+
js = null;
134+
}
135+
SolidClientException.jsonService = js;
136+
SolidClientException.jsonServiceInitialized = true;
137+
return SolidClientException.jsonService;
138+
}
139+
140+
public static SolidClientException fromErrorResponse(
141+
final String message,
142+
final URI uri,
143+
final int code,
144+
final Headers headers,
145+
final byte[] body
146+
) {
147+
ProblemDetails pd;
148+
final JsonService jsonService = getJsonService();
149+
if (
150+
jsonService == null
151+
|| (headers != null && !headers.allValues("Content-Type").contains(ProblemDetails.MIME_TYPE))) {
152+
pd = new ProblemDetails(null, HttpStatus.getStatusMessage(code), null, code, null);
153+
return SolidClientException.handle(message, pd, uri, headers, new String(body));
154+
}
155+
try {
156+
// ProblemDetails doesn't have a default constructor, and we can't use JSON mapping annotations because
157+
// the JSON service is an abstraction over JSON-B and Jackson, so we deserialize the JSON object in a Map
158+
// and build the ProblemDetails from the Map values.
159+
final Map<String, Object> pdData = jsonService.fromJson(
160+
new ByteArrayInputStream(body),
161+
new HashMap<String, Object>(){}.getClass().getGenericSuperclass()
162+
);
163+
final String title = (String) pdData.get("title");
164+
final String details = (String) pdData.get("details");
165+
final URI type = URI.create((String) pdData.get("type"));
166+
final URI instance = URI.create((String) pdData.get("instance"));
167+
final int status = (int) pdData.get("status");
168+
pd = new ProblemDetails(type, title, details, status, instance);
169+
} catch (IOException e) {
170+
pd = new ProblemDetails( null, HttpStatus.getStatusMessage(code), null, code, null);
171+
}
172+
return SolidClientException.handle(message, pd, uri, headers, new String(body));
173+
}
174+
110175
/**
111176
*
112177
* @param message the resulting exception message

0 commit comments

Comments
 (0)