Skip to content

Commit c1406d7

Browse files
committed
Polishing.
Align Object Mapping with imperative approach. Refactor read methods to improve empty handling without the use of exceptions. Revert code reorganization. Improve encapsulation. Reformat code. Simplify tests. See gh-576 Original pull request: gh-807
1 parent c303f55 commit c1406d7

28 files changed

+508
-419
lines changed

spring-vault-core/src/main/java/org/springframework/vault/client/VaultResponses.java

Lines changed: 0 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@
3333
import org.springframework.util.Assert;
3434
import org.springframework.util.StringUtils;
3535
import org.springframework.vault.VaultException;
36-
import org.springframework.vault.support.VaultResponseDataVersion2;
3736
import org.springframework.vault.support.VaultResponseSupport;
3837
import org.springframework.web.client.HttpStatusCodeException;
3938

@@ -135,68 +134,6 @@ public Type getType() {
135134
};
136135
}
137136

138-
public static <T> ParameterizedTypeReference<VaultResponseSupport<T>> getTypeReference(
139-
final ParameterizedTypeReference<T> responseType) {
140-
141-
Assert.notNull(responseType, "Response type must not be null");
142-
143-
final Type supportType = new ParameterizedType() {
144-
145-
@Override
146-
public Type[] getActualTypeArguments() {
147-
return new Type[] { responseType.getType() };
148-
}
149-
150-
@Override
151-
public Type getRawType() {
152-
return VaultResponseSupport.class;
153-
}
154-
155-
@Override
156-
public Type getOwnerType() {
157-
return VaultResponseSupport.class;
158-
}
159-
};
160-
161-
return new ParameterizedTypeReference<VaultResponseSupport<T>>() {
162-
@Override
163-
public Type getType() {
164-
return supportType;
165-
}
166-
};
167-
}
168-
169-
public static <T> ParameterizedTypeReference<VaultResponseDataVersion2<T>> getDataTypeReference(
170-
final Class<T> responseType) {
171-
172-
Assert.notNull(responseType, "Response type must not be null");
173-
174-
final Type supportType = new ParameterizedType() {
175-
176-
@Override
177-
public Type[] getActualTypeArguments() {
178-
return new Type[] { responseType };
179-
}
180-
181-
@Override
182-
public Type getRawType() {
183-
return VaultResponseDataVersion2.class;
184-
}
185-
186-
@Override
187-
public Type getOwnerType() {
188-
return VaultResponseDataVersion2.class;
189-
}
190-
};
191-
192-
return new ParameterizedTypeReference<VaultResponseDataVersion2<T>>() {
193-
@Override
194-
public Type getType() {
195-
return supportType;
196-
}
197-
};
198-
}
199-
200137
/**
201138
* Obtain the error message from a JSON response.
202139
* @param json must not be {@literal null}.
Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,15 @@
44
import java.time.Instant;
55
import java.time.format.DateTimeFormatter;
66
import java.time.temporal.TemporalAccessor;
7+
import java.util.Collections;
8+
import java.util.HashMap;
9+
import java.util.LinkedHashMap;
710
import java.util.List;
811
import java.util.Map;
912
import java.util.stream.Collectors;
13+
1014
import org.springframework.lang.Nullable;
15+
import org.springframework.util.Assert;
1116
import org.springframework.util.StringUtils;
1217
import org.springframework.vault.support.DurationParser;
1318
import org.springframework.vault.support.VaultMetadataResponse;
@@ -16,8 +21,16 @@
1621
import org.springframework.vault.support.Versioned.Metadata.MetadataBuilder;
1722
import org.springframework.vault.support.Versioned.Version;
1823

19-
class VaultKeyValueUtilities {
24+
/**
25+
* Common utility methods to map raw vault data structures to Spring Vault objects
26+
*
27+
* @author Timothy R. Weiand
28+
* @author Mark Paluch
29+
* @since 3.1
30+
*/
31+
class KeyValueUtilities {
2032

33+
@SuppressWarnings("unchecked")
2134
static Metadata getMetadata(Map<String, Object> responseMetadata) {
2235

2336
MetadataBuilder builder = Metadata.builder();
@@ -34,6 +47,8 @@ static Metadata getMetadata(Map<String, Object> responseMetadata) {
3447
builder.destroyed();
3548
}
3649

50+
builder.customMetadata((Map) responseMetadata.get("custom_metadata"));
51+
3752
Integer version = (Integer) responseMetadata.get("version");
3853
builder.version(Version.from(version));
3954

@@ -95,4 +110,24 @@ private static Versioned.Metadata buildVersion(String version, Map<String, Objec
95110
.build();
96111
}
97112

113+
static Map<String, Object> createPatchRequest(Map<String, ?> patch, Map<String, Object> previous,
114+
Map<String, Object> metadata) {
115+
116+
Map<String, Object> result = new LinkedHashMap<>(previous);
117+
result.putAll(patch);
118+
119+
Map<String, Object> body = new HashMap<>();
120+
body.put("data", result);
121+
body.put("options", Collections.singletonMap("cas", metadata.get("version")));
122+
123+
return body;
124+
}
125+
126+
static String normalizeListPath(String path) {
127+
128+
Assert.notNull(path, "Path must not be null");
129+
130+
return path.equals("/") ? "" : path.endsWith("/") ? path : path + "/";
131+
}
132+
98133
}

spring-vault-core/src/main/java/org/springframework/vault/core/ReactiveKeyValueHelper.java

Lines changed: 0 additions & 52 deletions
This file was deleted.

spring-vault-core/src/main/java/org/springframework/vault/core/ReactiveVaultKeyValue1Template.java

Lines changed: 32 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2018-2022 the original author or authors.
2+
* Copyright 2023 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,24 +16,28 @@
1616
package org.springframework.vault.core;
1717

1818
import java.util.Map;
19-
import org.springframework.core.ParameterizedTypeReference;
19+
20+
import com.fasterxml.jackson.databind.JsonNode;
21+
import reactor.core.publisher.Flux;
22+
import reactor.core.publisher.Mono;
23+
2024
import org.springframework.util.Assert;
2125
import org.springframework.vault.core.VaultKeyValueOperationsSupport.KeyValueBackend;
2226
import org.springframework.vault.support.VaultResponse;
2327
import org.springframework.vault.support.VaultResponseSupport;
24-
import org.springframework.web.reactive.function.client.WebClientResponseException;
25-
import reactor.core.publisher.Flux;
26-
import reactor.core.publisher.Mono;
2728

2829
/**
2930
* Default implementation of {@link ReactiveVaultKeyValueOperations} for the Key/Value
3031
* backend version 1.
3132
*
3233
* @author Timothy R. Weiand
34+
* @author Mark Paluch
3335
* @since 3.1
3436
*/
3537
class ReactiveVaultKeyValue1Template extends ReactiveVaultKeyValueAccessor implements ReactiveVaultKeyValueOperations {
3638

39+
private final String path;
40+
3741
/**
3842
* Create a new {@link ReactiveVaultKeyValue1Template} given
3943
* {@link ReactiveVaultOperations} and the mount {@code path}.
@@ -43,6 +47,7 @@ class ReactiveVaultKeyValue1Template extends ReactiveVaultKeyValueAccessor imple
4347
public ReactiveVaultKeyValue1Template(ReactiveVaultOperations vaultOperations, String path) {
4448

4549
super(vaultOperations, path);
50+
this.path = path;
4651
}
4752

4853
@Override
@@ -53,22 +58,28 @@ public Flux<String> list(String path) {
5358
@Override
5459
@SuppressWarnings("unchecked")
5560
public Mono<VaultResponse> get(String path) {
56-
ParameterizedTypeReference<Map<String, Object>> ref = new ParameterizedTypeReference<>() {
57-
};
58-
59-
return doRead(path, ref).onErrorResume(WebClientResponseException.NotFound.class, e -> Mono.empty())
60-
.map(response -> {
61-
VaultResponse vaultResponse = new VaultResponse();
62-
VaultResponseSupport.updateWithoutData(vaultResponse, response);
63-
vaultResponse.setData(response.getData());
64-
return vaultResponse;
65-
});
61+
62+
return doRead(path, Map.class, (response, map) -> {
63+
VaultResponse vaultResponse = new VaultResponse();
64+
VaultResponseSupport.updateWithoutData(vaultResponse, response);
65+
vaultResponse.setData(map);
66+
return vaultResponse;
67+
});
6668
}
6769

6870
@Override
71+
@SuppressWarnings({ "rawtypes", "unchecked" })
6972
public <T> Mono<VaultResponseSupport<T>> get(String path, Class<T> responseType) {
7073

71-
return doRead(path, responseType).onErrorResume(WebClientResponseException.NotFound.class, e -> Mono.empty());
74+
Assert.hasText(path, "Path must not be empty");
75+
Assert.notNull(responseType, "Response type must not be null");
76+
77+
return doRead(path, responseType, (response, data) -> {
78+
79+
VaultResponseSupport result = response;
80+
result.setData(data);
81+
return result;
82+
});
7283
}
7384

7485
@Override
@@ -89,6 +100,11 @@ public KeyValueBackend getApiVersion() {
89100
return KeyValueBackend.KV_1;
90101
}
91102

103+
@Override
104+
JsonNode getJsonNode(VaultResponseSupport<JsonNode> response) {
105+
return response.getRequiredData();
106+
}
107+
92108
@Override
93109
String createDataPath(String path) {
94110
return String.format("%s/%s", this.path, path);

spring-vault-core/src/main/java/org/springframework/vault/core/ReactiveVaultKeyValue2Accessor.java

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2018-2022 the original author or authors.
2+
* Copyright 2023 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,23 +16,24 @@
1616
package org.springframework.vault.core;
1717

1818
import java.util.List;
19-
import java.util.Map;
20-
import org.springframework.core.ParameterizedTypeReference;
21-
import org.springframework.vault.client.VaultResponses;
19+
2220
import org.springframework.vault.core.VaultKeyValueOperationsSupport.KeyValueBackend;
2321
import org.springframework.vault.support.VaultResponseSupport;
22+
23+
import com.fasterxml.jackson.databind.JsonNode;
2424
import reactor.core.publisher.Flux;
2525

2626
/**
2727
* Support class to build accessor methods for the Vault key-value backend version 2.
2828
*
2929
* @author Timothy R. Weiand
30+
* @author Mark Paluch
3031
* @since 3.1
3132
* @see KeyValueBackend#KV_2
3233
*/
3334
abstract class ReactiveVaultKeyValue2Accessor extends ReactiveVaultKeyValueAccessor {
3435

35-
final String path;
36+
private final String path;
3637

3738
/**
3839
* Create a new {@link ReactiveVaultKeyValue2Accessor} given {@link VaultOperations}
@@ -51,22 +52,13 @@ abstract class ReactiveVaultKeyValue2Accessor extends ReactiveVaultKeyValueAcces
5152
@SuppressWarnings("unchecked")
5253
public Flux<String> list(String path) {
5354

54-
String pathToUse = path.equals("/") ? "" : path.endsWith("/") ? path : (path + "/");
55-
56-
// TODO: to test - null returns empty
57-
ParameterizedTypeReference<VaultResponseSupport<Map<String, Object>>> type = VaultResponses
58-
.getTypeReference(new ParameterizedTypeReference<>() {
59-
});
60-
61-
return doReadRaw(String.format("%s?list=true", createBackendPath("metadata", pathToUse)), type, false)
62-
.flatMap(ReactiveKeyValueHelper::getRequiredData)
55+
return doRead(
56+
String.format("%s?list=true", createBackendPath("metadata", KeyValueUtilities.normalizeListPath(path))),
57+
VaultListResponse.class)
6358
.flatMapMany(response -> {
64-
final List<String> list = (List<String>) response.get("keys");
65-
if (null == list) {
66-
return Flux.empty();
67-
}
68-
return Flux.fromIterable(list);
6959

60+
List<String> list = (List<String>) response.getRequiredData().get("keys");
61+
return null == list ? Flux.empty() : Flux.fromIterable(list);
7062
});
7163
}
7264

@@ -75,6 +67,12 @@ public KeyValueBackend getApiVersion() {
7567
return KeyValueBackend.KV_2;
7668
}
7769

70+
@Override
71+
JsonNode getJsonNode(VaultResponseSupport<JsonNode> response) {
72+
return response.getRequiredData().at("/data");
73+
}
74+
75+
@Override
7876
String createDataPath(String path) {
7977
return createBackendPath("data", path);
8078
}

0 commit comments

Comments
 (0)