Skip to content

Commit b3cab9a

Browse files
authored
Merge branch 'main' into remove-deprecations
2 parents c35363a + 55aa6b2 commit b3cab9a

File tree

4 files changed

+178
-0
lines changed

4 files changed

+178
-0
lines changed

solid/src/test/java/com/inrupt/client/solid/SolidClientTest.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,24 @@ void testCustomHeaders() throws Exception {
129129
}).toCompletableFuture().join();
130130
}
131131

132+
@Test
133+
void testJsonResource() {
134+
final URI uri = URI.create(config.get("solid_resource_uri") + "/transaction");
135+
client.read(uri, TransactionResource.class).thenAccept(res -> {
136+
try (final TransactionResource tr = res) {
137+
final var transaction = tr.getTransaction();
138+
assertEquals("sample description", transaction.description());
139+
assertEquals(TransactionResource.TransactionType.CREDIT, transaction.type());
140+
final var err = assertThrows(CompletionException.class, client.update(tr).toCompletableFuture()::join);
141+
assertTrue(err.getCause() instanceof ForbiddenException);
142+
tr.setTransaction(TransactionResource.Transaction.newBuilder(transaction)
143+
.type(TransactionResource.TransactionType.DEBIT)
144+
.description("different description")
145+
.build());
146+
assertDoesNotThrow(client.update(tr).toCompletableFuture()::join);
147+
}
148+
}).toCompletableFuture().join();
149+
}
132150

133151
@Test
134152
void testGetPlaylist() throws IOException, InterruptedException {

solid/src/test/java/com/inrupt/client/solid/SolidMockHttpService.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,26 @@ private void setupMocks() {
216216
.willReturn(aResponse()
217217
.withStatus(204)));
218218

219+
wireMockServer.stubFor(get(urlEqualTo("/transaction"))
220+
.withHeader("User-Agent", equalTo(USER_AGENT))
221+
.willReturn(aResponse()
222+
.withStatus(200)
223+
.withHeader("Content-Type", "application/json")
224+
.withBodyFile("transaction.json")));
225+
226+
wireMockServer.stubFor(put(urlEqualTo("/transaction"))
227+
.withHeader("User-Agent", equalTo(USER_AGENT))
228+
.withRequestBody(containing("DEBIT"))
229+
.withRequestBody(containing("different description"))
230+
.willReturn(aResponse()
231+
.withStatus(204)));
232+
233+
wireMockServer.stubFor(put(urlEqualTo("/transaction"))
234+
.withHeader("User-Agent", equalTo(USER_AGENT))
235+
.withRequestBody(containing("CREDIT"))
236+
.willReturn(aResponse()
237+
.withStatus(403)));
238+
219239
wireMockServer.stubFor(get(urlEqualTo("/binary"))
220240
.atPriority(1)
221241
.withHeader("User-Agent", equalTo(USER_AGENT))
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
/*
2+
* Copyright Inrupt Inc.
3+
*
4+
* Permission is hereby granted, free of charge, to any person obtaining a copy
5+
* of this software and associated documentation files (the "Software"), to deal in
6+
* the Software without restriction, including without limitation the rights to use,
7+
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
8+
* Software, and to permit persons to whom the Software is furnished to do so,
9+
* subject to the following conditions:
10+
*
11+
* The above copyright notice and this permission notice shall be included in
12+
* all copies or substantial portions of the Software.
13+
*
14+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
15+
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
16+
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
17+
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
18+
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
19+
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20+
*/
21+
package com.inrupt.client.solid;
22+
23+
import com.inrupt.client.spi.JsonService;
24+
import com.inrupt.client.spi.ServiceProvider;
25+
26+
import java.io.ByteArrayInputStream;
27+
import java.io.ByteArrayOutputStream;
28+
import java.io.IOException;
29+
import java.io.InputStream;
30+
import java.io.UncheckedIOException;
31+
import java.net.URI;
32+
import java.time.Instant;
33+
import java.util.Objects;
34+
35+
class TransactionResource extends SolidNonRDFSource {
36+
37+
private final JsonService jsonService;
38+
39+
private Transaction transaction;
40+
41+
public TransactionResource(final URI identifier, final String contentType, final InputStream entity) {
42+
super(identifier, contentType, entity);
43+
44+
this.jsonService = ServiceProvider.getJsonService();
45+
try {
46+
this.transaction = jsonService.fromJson(super.getEntity(), Transaction.class);
47+
} catch (IOException ex) {
48+
throw new UncheckedIOException("Unable to parse Transaction data", ex);
49+
}
50+
}
51+
52+
public Transaction getTransaction() {
53+
return transaction;
54+
}
55+
56+
public void setTransaction(final Transaction transaction) {
57+
this.transaction = Objects.requireNonNull(transaction, "transaction may not be null!");
58+
}
59+
60+
@Override
61+
public InputStream getEntity() throws IOException {
62+
try (final ByteArrayOutputStream output = new ByteArrayOutputStream()) {
63+
jsonService.toJson(transaction, output);
64+
return new ByteArrayInputStream(output.toByteArray());
65+
}
66+
}
67+
68+
record Transaction(String id, String description, Instant date, double amount, TransactionType type,
69+
String category) {
70+
static class Builder {
71+
private String transactionId;
72+
private String transactionDescription;
73+
private Instant transactionDate;
74+
private double transactionAmount;
75+
private TransactionType transactionType;
76+
private String transactionCategory;
77+
78+
public Builder id(final String id) {
79+
this.transactionId = id;
80+
return this;
81+
}
82+
83+
public Builder description(final String description) {
84+
this.transactionDescription = description;
85+
return this;
86+
}
87+
88+
public Builder date(final Instant date) {
89+
this.transactionDate = date;
90+
return this;
91+
}
92+
93+
public Builder amount(final double amount) {
94+
this.transactionAmount = amount;
95+
return this;
96+
}
97+
98+
public Builder type(final TransactionType type) {
99+
this.transactionType = type;
100+
return this;
101+
}
102+
103+
public Builder category(final String category) {
104+
this.transactionCategory = category;
105+
return this;
106+
}
107+
108+
public Transaction build() {
109+
return new Transaction(this.transactionId, this.transactionDescription, this.transactionDate,
110+
this.transactionAmount, this.transactionType, this.transactionCategory);
111+
}
112+
}
113+
114+
static Builder newBuilder() {
115+
return new Builder();
116+
}
117+
118+
static Builder newBuilder(final Transaction transaction) {
119+
return new Builder()
120+
.id(transaction.id())
121+
.description(transaction.description())
122+
.date(transaction.date())
123+
.amount(transaction.amount())
124+
.type(transaction.type())
125+
.category(transaction.category());
126+
}
127+
}
128+
129+
enum TransactionType {
130+
CREDIT, DEBIT
131+
}
132+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"id": "testid",
3+
"date": "2025-09-28T15:37:00Z",
4+
"description": "sample description",
5+
"amount": 20.12,
6+
"type": "CREDIT",
7+
"category": "groceries"
8+
}

0 commit comments

Comments
 (0)