diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1e6e166..de32017 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,9 @@
+## unreleased
+
+### Fix
+* Fixed JSON type conversion in `SecretResponse#get(String, Class)` (#67)
+
+
## 1.1.4 (2023-06-15)
### Fix
diff --git a/pom.xml b/pom.xml
index 3842e6e..6c459e8 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
de.stklcode.jvault
jvault-connector
- 1.1.4
+ 1.1.5-SNAPSHOT
jar
diff --git a/src/main/java/de/stklcode/jvault/connector/model/response/SecretResponse.java b/src/main/java/de/stklcode/jvault/connector/model/response/SecretResponse.java
index 405e070..55d79a9 100644
--- a/src/main/java/de/stklcode/jvault/connector/model/response/SecretResponse.java
+++ b/src/main/java/de/stklcode/jvault/connector/model/response/SecretResponse.java
@@ -79,8 +79,12 @@ public abstract class SecretResponse extends VaultDataResponse {
Object rawValue = get(key);
if (rawValue == null) {
return null;
+ } else if (type.isInstance(rawValue)) {
+ return type.cast(rawValue);
+ } else {
+ var om = new ObjectMapper();
+ return om.readValue(om.writeValueAsString(rawValue), type);
}
- return new ObjectMapper().readValue(rawValue.toString(), type);
} catch (IOException e) {
throw new InvalidResponseException("Unable to parse response payload: " + e.getMessage());
}
diff --git a/src/test/java/de/stklcode/jvault/connector/model/response/PlainSecretResponseTest.java b/src/test/java/de/stklcode/jvault/connector/model/response/PlainSecretResponseTest.java
index 7372699..5a69ed9 100644
--- a/src/test/java/de/stklcode/jvault/connector/model/response/PlainSecretResponseTest.java
+++ b/src/test/java/de/stklcode/jvault/connector/model/response/PlainSecretResponseTest.java
@@ -16,11 +16,13 @@
package de.stklcode.jvault.connector.model.response;
+import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonProcessingException;
+import de.stklcode.jvault.connector.exception.InvalidResponseException;
import de.stklcode.jvault.connector.model.AbstractModelTest;
import org.junit.jupiter.api.Test;
-import java.util.List;
+import java.util.*;
import static org.junit.jupiter.api.Assertions.*;
@@ -85,4 +87,131 @@ class PlainSecretResponseTest extends AbstractModelTest {
assertEquals(SECRET_DATA_V1, res.get(SECRET_DATA_K1), "Response does not contain correct data");
assertEquals(SECRET_DATA_V2, res.get(SECRET_DATA_K2), "Response does not contain correct data");
}
+
+ /**
+ * Test creation from JSON value as returned by Vault (JSON example copied from Vault documentation).
+ */
+ @Test
+ void testGetter() {
+ final var stringKey = "string";
+ final var stringVal = "test";
+
+ final var numberKey = "number";
+ final var numberVal = 123.45;
+
+ final var listKey = "list";
+ final var listVal = List.of("foo", "bar");
+
+ final var complexKey = "complex";
+ final var complexVal = new ComplexType("val1", 678);
+
+ SecretResponse res = assertDoesNotThrow(
+ () -> objectMapper.readValue(
+ "{\n" +
+ " \"request_id\": \"req-id\",\n" +
+ " \"lease_id\": \"lea-id\",\n" +
+ " \"lease_duration\": " + 123456 + ",\n" +
+ " \"renewable\": true,\n" +
+ " \"data\": {\n" +
+ " \"" + stringKey + "\": \"" + stringVal + "\",\n" +
+ " \"" + numberKey + "\": \"" + numberVal + "\",\n" +
+ " \"" + listKey + "\": [\"" + String.join("\", \"", listVal) + "\"],\n" +
+ " \"" + complexKey + "\": {" +
+ " \"field1\": \"" + complexVal.field1 + "\",\n" +
+ " \"field2\": " + complexVal.field2 + "\n" +
+ " }\n" +
+ " }\n" +
+ "}",
+ PlainSecretResponse.class
+ ),
+ "SecretResponse deserialization failed"
+ );
+
+ assertEquals(stringVal, res.get(stringKey), "unexpected value for string (implicit)");
+ assertEquals(
+ stringVal,
+ assertDoesNotThrow(() -> res.get(stringKey, String.class), "getting string failed"),
+ "unexpected value for string (explicit)"
+ );
+
+ assertEquals(String.valueOf(numberVal), res.get(numberKey), "unexpected value for number (implicit)");
+ assertEquals(
+ numberVal,
+ assertDoesNotThrow(() -> res.get(numberKey, Double.class), "getting number failed"),
+ "unexpected value for number (explicit)"
+ );
+ assertEquals(
+ String.valueOf(numberVal),
+ assertDoesNotThrow(() -> res.get(numberKey, String.class), "getting number as string failed"),
+ "unexpected value for number as string (explicit)"
+ );
+
+ assertEquals(listVal, res.get(listKey), "unexpected value for list (implicit)");
+ assertEquals(
+ listVal,
+ assertDoesNotThrow(() -> res.get(listKey, ArrayList.class), "getting list failed"),
+ "unexpected value for list (explicit)"
+ );
+
+ assertEquals(complexVal.toMap(), res.get(complexKey), "unexpected value for complex type (implicit)");
+ assertEquals(
+ complexVal.toMap(),
+ assertDoesNotThrow(() -> res.get(complexKey, HashMap.class), "getting complex type as map failed"),
+ "unexpected value for complex type as map (explicit)"
+ );
+ assertEquals(
+ complexVal,
+ assertDoesNotThrow(() -> res.get(complexKey, ComplexType.class), "getting complex type failed"),
+ "unexpected value for complex type (explicit)"
+ );
+ assertThrows(
+ InvalidResponseException.class,
+ () -> res.get(complexKey, Integer.class),
+ "getting complex type as integer should fail"
+ );
+ }
+
+
+ /**
+ * Test class for complex field mapping.
+ */
+ private static class ComplexType {
+ @JsonProperty("field1")
+ private String field1;
+
+ @JsonProperty("field2")
+ private Integer field2;
+
+ private ComplexType() {
+ // Required for JSON deserialization.
+ }
+
+ private ComplexType(String field1, Integer field2) {
+ this.field1 = field1;
+ this.field2 = field2;
+ }
+
+ private Map toMap() {
+ return Map.of(
+ "field1", field1,
+ "field2", field2
+ );
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ } else if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ ComplexType that = (ComplexType) o;
+ return Objects.equals(field1, that.field1) && Objects.equals(field2, that.field2);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(field1, field2);
+ }
+ }
}