diff --git a/docs/documentation/server_admin/topics/admin-cli.adoc b/docs/documentation/server_admin/topics/admin-cli.adoc index 623cbe524e..2e41a8d84c 100644 --- a/docs/documentation/server_admin/topics/admin-cli.adoc +++ b/docs/documentation/server_admin/topics/admin-cli.adoc @@ -192,6 +192,13 @@ In this example, you start a session authenticated as the `admin` user in the `m The `create` and `update` commands send a JSON body to the server. You can use `-f FILENAME` to read a pre-made document from a file. When you can use the `-f -` option, {project_name} reads the message body from the standard input. You can specify individual attributes and their values, as seen in the `create users` example. {project_name} composes the attributes into a JSON body and sends them to the server. +[NOTE] +==== +The value in name=value pairs used in --set, -s options, are assumed to be JSON. If it cannot be parsed as valid JSON, then it will be sent to the server as a text value. + +If the value is enclosed in quotes after shell processing, but is not valid JSON, the quotes will be stripped and the rest of the value will be sent as text. This behavior is deprecated, please consider specifying your value without qoutes or a valid JSON string literal with double quotes. +==== + Several methods are available in {project_name} to update a resource using the `update` command. You can determine the current state of a resource and save it to a file, edit that file, and send it to the server for an update. For example: diff --git a/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/admin/cli/util/OutputUtil.java b/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/admin/cli/util/OutputUtil.java index ef49f98b50..8e3c083e58 100644 --- a/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/admin/cli/util/OutputUtil.java +++ b/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/admin/cli/util/OutputUtil.java @@ -17,6 +17,7 @@ package org.keycloak.client.admin.cli.util; import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; @@ -37,6 +38,7 @@ public class OutputUtil { static { MAPPER.enable(SerializationFeature.INDENT_OUTPUT); + MAPPER.enable(DeserializationFeature.FAIL_ON_TRAILING_TOKENS); MAPPER.setSerializationInclusion(JsonInclude.Include.NON_NULL); } diff --git a/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/admin/cli/util/ReflectionUtil.java b/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/admin/cli/util/ReflectionUtil.java index 81c2d29b12..4a0774502a 100644 --- a/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/admin/cli/util/ReflectionUtil.java +++ b/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/admin/cli/util/ReflectionUtil.java @@ -18,9 +18,6 @@ package org.keycloak.client.admin.cli.util; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ArrayNode; -import com.fasterxml.jackson.databind.node.BooleanNode; -import com.fasterxml.jackson.databind.node.DoubleNode; -import com.fasterxml.jackson.databind.node.LongNode; import com.fasterxml.jackson.databind.node.NullNode; import com.fasterxml.jackson.databind.node.ObjectNode; import com.fasterxml.jackson.databind.node.TextNode; @@ -127,54 +124,21 @@ public class ReflectionUtil { list.remove(index); } - private static JsonNode valueToJsonNode(String val) { - // try get value as JSON object + static JsonNode valueToJsonNode(String val) { + // try get value as JSON try { - return MAPPER.readValue(val, ObjectNode.class); + return MAPPER.readTree(val); } catch (Exception ignored) { } - // try get value as JSON array - try { - return MAPPER.readValue(val, ArrayNode.class); - } catch (Exception ignored) { - } - - if (isBoolean(val)) { - return BooleanNode.valueOf(Boolean.valueOf(val)); - } else if (isInteger(val)) { - return LongNode.valueOf(Long.valueOf(val)); - } else if (isNumber(val)) { - return DoubleNode.valueOf(Double.valueOf(val)); - } else if (isQuoted(val)) { + // legacy behavior, check for quoted / invalid json - to be removed + if (isQuoted(val)) { return TextNode.valueOf(unquote(val)); } return TextNode.valueOf(val); } - - private static boolean isInteger(String val) { - try { - Long.valueOf(val); - return true; - } catch (Exception ignored) { - return false; - } - } - - private static boolean isNumber(String val) { - try { - Double.valueOf(val); - return true; - } catch (Exception ignored) { - return false; - } - } - - private static boolean isBoolean(String val) { - return "false".equals(val) || "true".equals(val); - } - + private static boolean isQuoted(String val) { return val.startsWith("'") || val.startsWith("\""); } diff --git a/integration/client-cli/admin-cli/src/test/java/org/keycloak/client/admin/cli/util/ReflectionUtilTest.java b/integration/client-cli/admin-cli/src/test/java/org/keycloak/client/admin/cli/util/ReflectionUtilTest.java new file mode 100644 index 0000000000..76adcebe78 --- /dev/null +++ b/integration/client-cli/admin-cli/src/test/java/org/keycloak/client/admin/cli/util/ReflectionUtilTest.java @@ -0,0 +1,47 @@ +/* + * Copyright 2016 Red Hat, Inc. and/or its affiliates + * and other contributors as indicated by the @author tags. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.keycloak.client.admin.cli.util; + +import org.junit.Test; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.NumericNode; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +public class ReflectionUtilTest { + + @Test + public void testValueToJsonNode() { + assertEquals("x", ReflectionUtil.valueToJsonNode("x").asText()); + assertEquals("x", ReflectionUtil.valueToJsonNode("'x'").asText()); + assertEquals("x", ReflectionUtil.valueToJsonNode("\"x\"").asText()); + assertEquals("x\"y", ReflectionUtil.valueToJsonNode("\"x\"y\"").asText()); + // should preserve the leading 0 + assertEquals("0123", ReflectionUtil.valueToJsonNode("0123").asText()); + JsonNode value = ReflectionUtil.valueToJsonNode("123"); + assertTrue(value instanceof NumericNode); + assertEquals(123, value.asInt()); + value = ReflectionUtil.valueToJsonNode("[\"x\",\"y\"]"); + assertTrue(value instanceof ArrayNode); + assertEquals("y", value.get(1).textValue()); + } + +}