mirror of
https://github.com/keycloak/keycloak.git
synced 2026-05-27 20:02:59 -04:00
Use a custom serializer to write policy config values as JSON array objects instead of a stringfied array
Closes #44573 Signed-off-by: Stefan Guilhen <sguilhen@redhat.com>
This commit is contained in:
parent
e8c6a7b98d
commit
032158901b
3 changed files with 121 additions and 2 deletions
|
|
@ -0,0 +1,62 @@
|
|||
package org.keycloak.representations.idm.authorization;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.core.JsonToken;
|
||||
import com.fasterxml.jackson.databind.DeserializationContext;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
|
||||
import com.fasterxml.jackson.databind.node.ArrayNode;
|
||||
|
||||
public class PolicyConfigDeserializer extends StdDeserializer<Map<String,String>> {
|
||||
|
||||
public PolicyConfigDeserializer() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
public PolicyConfigDeserializer(Class<Map<String, String>> t) {
|
||||
super(t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> deserialize(JsonParser parser, DeserializationContext context) throws IOException {
|
||||
|
||||
// ensure we are at the start of the JSON object for the map
|
||||
if (parser.currentToken() != JsonToken.START_OBJECT) {
|
||||
context.reportWrongTokenException(Map.class, JsonToken.START_OBJECT,
|
||||
"Expected START_OBJECT for config map");
|
||||
}
|
||||
|
||||
Map<String, String> map = new HashMap<>();
|
||||
ObjectMapper mapper = (ObjectMapper) parser.getCodec();
|
||||
|
||||
// loop through key-value pairs in the JSON object
|
||||
while (parser.nextToken() != JsonToken.END_OBJECT) {
|
||||
// get the key and value
|
||||
String key = parser.currentName();
|
||||
parser.nextToken();
|
||||
|
||||
// check the type of the value token
|
||||
if (parser.currentToken() == JsonToken.START_ARRAY) {
|
||||
// case 1: value is a JSON array
|
||||
ArrayNode arrayNode = mapper.readTree(parser);
|
||||
|
||||
// convert the ArrayNode back into a single string (the original format)
|
||||
String originalStringFormat = arrayNode.toString();
|
||||
map.put(key, originalStringFormat);
|
||||
} else if (parser.currentToken() == JsonToken.VALUE_STRING) {
|
||||
// case 2: value is a JSON String (the regular case)
|
||||
String value = parser.getText();
|
||||
map.put(key, value);
|
||||
} else {
|
||||
// handle other unexpected types, if necessary
|
||||
context.reportWrongTokenException(Map.class, parser.currentToken(),
|
||||
"Expected String or Array for config value");
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
package org.keycloak.representations.idm.authorization;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.SerializerProvider;
|
||||
import com.fasterxml.jackson.databind.node.ArrayNode;
|
||||
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
|
||||
|
||||
public class PolicyConfigSerializer extends StdSerializer<Map<String, String>> {
|
||||
|
||||
private static final ObjectMapper MAPPER = new ObjectMapper();
|
||||
|
||||
public PolicyConfigSerializer() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
public PolicyConfigSerializer(Class<Map<String, String>> t) {
|
||||
super(t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serialize(Map<String, String> map, JsonGenerator generator, SerializerProvider provider) throws IOException {
|
||||
generator.writeStartObject();
|
||||
|
||||
for (Map.Entry<String, String> entry : map.entrySet()) {
|
||||
String key = entry.getKey();
|
||||
String value = entry.getValue();
|
||||
|
||||
generator.writeFieldName(key);
|
||||
|
||||
// check if the value string looks like a JSON array
|
||||
if (value != null && value.startsWith("[\"") && value.endsWith("\"]")) {
|
||||
try {
|
||||
// attempt to read the string as a JSON node (which should be an ArrayNode)
|
||||
ArrayNode arrayNode = (ArrayNode) MAPPER.readTree(value);
|
||||
// write the ArrayNode directly to the generator
|
||||
generator.writeTree(arrayNode);
|
||||
} catch (Exception e) {
|
||||
// if parsing fails, write the value as a plain string
|
||||
generator.writeString(value);
|
||||
}
|
||||
} else {
|
||||
// not an array string, so write as a plain string
|
||||
generator.writeString(value);
|
||||
}
|
||||
}
|
||||
generator.writeEndObject();
|
||||
}
|
||||
}
|
||||
|
|
@ -19,12 +19,17 @@ package org.keycloak.representations.idm.authorization;
|
|||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||
*/
|
||||
public class PolicyRepresentation extends AbstractPolicyRepresentation {
|
||||
|
||||
private Map<String, String> config = new HashMap();
|
||||
@JsonSerialize(using = PolicyConfigSerializer.class)
|
||||
@JsonDeserialize(using = PolicyConfigDeserializer.class)
|
||||
private Map<String, String> config = new HashMap<>();
|
||||
|
||||
public Map<String, String> getConfig() {
|
||||
return this.config;
|
||||
|
|
@ -33,4 +38,4 @@ public class PolicyRepresentation extends AbstractPolicyRepresentation {
|
|||
public void setConfig(Map<String, String> config) {
|
||||
this.config = config;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue