Skip to content

Commit

Permalink
http: add json+jackson support (#27)
Browse files Browse the repository at this point in the history
* http: add json+jackson support

Signed-off-by: Edoardo Vacchi <[email protected]>

* switch to jackson as default

Signed-off-by: Edoardo Vacchi <[email protected]>

---------

Signed-off-by: Edoardo Vacchi <[email protected]>
  • Loading branch information
evacchi authored Jan 6, 2025
1 parent 5ccd11d commit 6086702
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 9 deletions.
7 changes: 7 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
<jimfs.version>1.3.0</jimfs.version>
<jakarta.json-api.version>2.1.3</jakarta.json-api.version>
<jakarta.json.version>1.1.7</jakarta.json.version>
<jackson-core.version>2.18.2</jackson-core.version>
</properties>

<dependencies>
Expand Down Expand Up @@ -104,6 +105,12 @@
<version>${jimfs.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson-core.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>jakarta.json</groupId>
<artifactId>jakarta.json-api</artifactId>
Expand Down
46 changes: 38 additions & 8 deletions src/main/java/org/extism/sdk/chicory/HttpConfig.java
Original file line number Diff line number Diff line change
@@ -1,32 +1,62 @@
package org.extism.sdk.chicory;

import java.util.Objects;

public class HttpConfig {
/**
* Use {@link JdkHttpClientAdapter} for the HTTP client adapter.
* Recommended on recent Java versions.
*/
public static HttpConfig defaultConfig() {
return new HttpConfig().withClientAdapter(new JdkHttpClientAdapter()).withJsonCodec(new JakartaJsonCodec());
return HttpConfig.builder()
.withClientAdapter(new JdkHttpClientAdapter())
.withJsonCodec(new JacksonJsonCodec()).build();
}

/**
* Use {@link HttpUrlConnectionClientAdapter} for the HTTP client adapter.
* Recommended for Android.
*/
public static HttpConfig urlConnectionConfig() {
return new HttpConfig().withClientAdapter(new HttpUrlConnectionClientAdapter()).withJsonCodec(new JakartaJsonCodec());
return HttpConfig.builder()
.withClientAdapter(new HttpUrlConnectionClientAdapter())
.withJsonCodec(new JakartaJsonCodec()).build();
}

public static Builder builder() {
return new Builder();
}

public static class Builder {
HttpJsonCodec httpJsonCodec;
HttpClientAdapter httpClientAdapter;

private Builder() {}

public Builder withJsonCodec(HttpJsonCodec httpJsonCodec) {
this.httpJsonCodec = httpJsonCodec;
return this;
}

public Builder withClientAdapter(HttpClientAdapter httpClientAdapter) {
this.httpClientAdapter = httpClientAdapter;
return this;
}

public HttpConfig build() {
Objects.requireNonNull(httpJsonCodec, "httpJsonCodec is required");
Objects.requireNonNull(httpClientAdapter, "httpClientAdapter is required");
return new HttpConfig(httpJsonCodec, httpClientAdapter);
}
}


HttpJsonCodec httpJsonCodec;
HttpClientAdapter httpClientAdapter;

public HttpConfig withJsonCodec(HttpJsonCodec httpJsonCodec) {
public HttpConfig(HttpJsonCodec httpJsonCodec, HttpClientAdapter httpClientAdapter) {
this.httpJsonCodec = httpJsonCodec;
return this;
}

public HttpConfig withClientAdapter(HttpClientAdapter httpClientAdapter) {
this.httpClientAdapter = httpClientAdapter;
return this;
}

}
70 changes: 70 additions & 0 deletions src/main/java/org/extism/sdk/chicory/JacksonJsonCodec.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package org.extism.sdk.chicory;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.IOException;
import java.net.URI;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class JacksonJsonCodec implements HttpJsonCodec {

ObjectMapper objectMapper = new ObjectMapper();

@Override
public RequestMetadata decodeMetadata(byte[] data) {

JsonNode request = null;
try {
request = objectMapper.readTree(data);
} catch (IOException e) {
throw new ExtismException(e);
}

var method = request.get("method").asText();
var uri = URI.create(request.get("url").asText());
var headers = request.get("headers");

Map<String, String> headersMap = new HashMap<>();
var fields = headers.fields();
while (fields.hasNext()) {
var entry = fields.next();
headersMap.put(entry.getKey(), entry.getValue().asText());
}

return new RequestMetadata() {
@Override
public String method() {
return method;
}

@Override
public URI uri() {
return uri;
}

@Override
public Map<String, String> headers() {
return headersMap;
}
};
}

public byte[] encodeHeaders(Map<String, List<String>> headers) {
// FIXME duplicated headers are effectively overwriting duplicate values!
var objectNode = objectMapper.createObjectNode();
for (var entry : headers.entrySet()) {
for (var v : entry.getValue()) {
objectNode.put(entry.getKey(), v);
}
}
try {
return objectMapper.writeValueAsBytes(objectNode);
} catch (JsonProcessingException e) {
throw new ExtismException(e);
}
}
}
2 changes: 1 addition & 1 deletion src/test/java/org/extism/sdk/chicory/HostEnvTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public void testShowcase() {
var logger = new SystemLogger();

var config = Map.of("key", "value");
var hostEnv = new HostEnv(new Kernel(), config, new String[0], new HttpConfig(), logger);
var hostEnv = new HostEnv(new Kernel(), config, new String[0], HttpConfig.defaultConfig(), logger);

assertEquals(hostEnv.config().get("key"), "value");

Expand Down

0 comments on commit 6086702

Please sign in to comment.