From 61c1a882d6851058520dbfb71fae47276f5c9080 Mon Sep 17 00:00:00 2001 From: Rahul Kumar Date: Mon, 3 Aug 2020 08:54:59 +0530 Subject: [PATCH] Added configuration support for type conversion using Map --- src/main/java/org/json/XML.java | 25 ++++++------- .../java/org/json/XMLParserConfiguration.java | 20 ++++++----- .../java/org/json/XMLXsiTypeConverter.java | 5 +++ src/test/java/org/json/junit/XMLTest.java | 35 +++++++++++++------ 4 files changed, 50 insertions(+), 35 deletions(-) create mode 100644 src/main/java/org/json/XMLXsiTypeConverter.java diff --git a/src/main/java/org/json/XML.java b/src/main/java/org/json/XML.java index 0ad6ce477..004a1f89b 100644 --- a/src/main/java/org/json/XML.java +++ b/src/main/java/org/json/XML.java @@ -261,7 +261,7 @@ private static boolean parse(XMLTokener x, JSONObject context, String name, XMLP String string; String tagName; Object token; - String typeCastClass; + XMLXsiTypeConverter xmlXsiTypeConverter; // Test for and skip past these forms: // @@ -341,7 +341,7 @@ private static boolean parse(XMLTokener x, JSONObject context, String name, XMLP token = null; jsonObject = new JSONObject(); boolean nilAttributeFound = false; - typeCastClass = null; + xmlXsiTypeConverter = null; for (;;) { if (token == null) { token = x.nextToken(); @@ -360,9 +360,9 @@ private static boolean parse(XMLTokener x, JSONObject context, String name, XMLP && NULL_ATTR.equals(string) && Boolean.parseBoolean((String) token)) { nilAttributeFound = true; - } else if(config.useValueTypeCast + } else if(config.xsiTypeMap != null && TYPE_ATTR.equals(string)) { - typeCastClass = (String) token; + xmlXsiTypeConverter = config.xsiTypeMap.get(token); } else if (!nilAttributeFound) { jsonObject.accumulate(string, config.isKeepStrings() @@ -401,9 +401,9 @@ private static boolean parse(XMLTokener x, JSONObject context, String name, XMLP } else if (token instanceof String) { string = (String) token; if (string.length() > 0) { - if(typeCastClass != null) { + if(xmlXsiTypeConverter != null) { jsonObject.accumulate(config.getcDataTagName(), - stringToValue(string, typeCastClass)); + stringToValue(string, xmlXsiTypeConverter)); } else { jsonObject.accumulate(config.getcDataTagName(), config.isKeepStrings() ? string : stringToValue(string)); @@ -435,17 +435,12 @@ private static boolean parse(XMLTokener x, JSONObject context, String name, XMLP /** * This method tries to convert the given string value to the target object * @param string String to convert - * @param className target class name + * @param typeConverter value converter to convert string to integer, boolean e.t.c * @return JSON value of this string or the string */ - public static Object stringToValue(String string, String className) { - try { - if(className.equals(String.class.getName())) return string; - Class clazz = Class.forName(className); - Method method = clazz.getMethod("valueOf", String.class); - return method.invoke(null, string); - } catch (Exception e){ - e.printStackTrace(); + public static Object stringToValue(String string, XMLXsiTypeConverter typeConverter) { + if(typeConverter != null) { + return typeConverter.convert(string); } return stringToValue(string); } diff --git a/src/main/java/org/json/XMLParserConfiguration.java b/src/main/java/org/json/XMLParserConfiguration.java index c57c8db36..b7057eef6 100644 --- a/src/main/java/org/json/XMLParserConfiguration.java +++ b/src/main/java/org/json/XMLParserConfiguration.java @@ -23,6 +23,9 @@ of this software and associated documentation files (the "Software"), to deal SOFTWARE. */ +import java.util.Map; + + /** * Configuration object for the XML parser. The configuration is immutable. * @author AylwardJ @@ -57,10 +60,9 @@ public class XMLParserConfiguration { private boolean convertNilAttributeToNull; /** - * When parsing the XML into JSON, specifies if values with attribute xsi:type="java.lang.Integer" - * should be kept as attribute(false), or they should be converted to the given type + * This will allow type conversion for values in XML if xsi:type attribute is defined */ - public boolean useValueTypeCast; + public Map> xsiTypeMap; /** * Default parser configuration. Does not keep strings (tries to implicitly convert @@ -129,7 +131,7 @@ public XMLParserConfiguration (final boolean keepStrings, final String cDataTagN */ @Deprecated public XMLParserConfiguration (final boolean keepStrings, final String cDataTagName, final boolean convertNilAttributeToNull) { - this(keepStrings, cDataTagName, convertNilAttributeToNull, false); + this(keepStrings, cDataTagName, convertNilAttributeToNull, null); } /** @@ -140,16 +142,16 @@ public XMLParserConfiguration (final boolean keepStrings, final String cDataTagN * to use that value as the JSONObject key name to process as CDATA. * @param convertNilAttributeToNull true to parse values with attribute xsi:nil="true" as null. * false to parse values with attribute xsi:nil="true" as {"xsi:nil":true}. - * @param useValueTypeCast true to parse values with attribute xsi:type="java.lang.Integer" as - * integer, xsi:type="java.lang.String" as string - * false to parse values with attribute xsi:type="java.lang.Integer" as {"xsi:type":"java.lang.Integer"}. + * @param xsiTypeMap new HashMap>() to parse values with attribute + * xsi:type="integer" as integer, xsi:type="string" as string + * null to use default behaviour. */ public XMLParserConfiguration (final boolean keepStrings, final String cDataTagName, - final boolean convertNilAttributeToNull, final boolean useValueTypeCast ) { + final boolean convertNilAttributeToNull, final Map> xsiTypeMap ) { this.keepStrings = keepStrings; this.cDataTagName = cDataTagName; this.convertNilAttributeToNull = convertNilAttributeToNull; - this.useValueTypeCast = useValueTypeCast; + this.xsiTypeMap = xsiTypeMap; } /** diff --git a/src/main/java/org/json/XMLXsiTypeConverter.java b/src/main/java/org/json/XMLXsiTypeConverter.java new file mode 100644 index 000000000..48e4ac18c --- /dev/null +++ b/src/main/java/org/json/XMLXsiTypeConverter.java @@ -0,0 +1,5 @@ +package org.json; + +public interface XMLXsiTypeConverter { + T convert(String value); +} diff --git a/src/test/java/org/json/junit/XMLTest.java b/src/test/java/org/json/junit/XMLTest.java index 2b6f065d5..82c0b3969 100644 --- a/src/test/java/org/json/junit/XMLTest.java +++ b/src/test/java/org/json/junit/XMLTest.java @@ -38,6 +38,8 @@ of this software and associated documentation files (the "Software"), to deal import java.io.InputStreamReader; import java.io.Reader; import java.io.StringReader; +import java.util.HashMap; +import java.util.Map; import org.json.JSONArray; import org.json.JSONException; @@ -45,6 +47,7 @@ of this software and associated documentation files (the "Software"), to deal import org.json.JSONTokener; import org.json.XML; import org.json.XMLParserConfiguration; +import org.json.XMLXsiTypeConverter; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; @@ -978,11 +981,10 @@ public void testIssue537CaseSensitiveHexUnEscapeDirect(){ */ @Test public void testToJsonWithTypeWhenTypeConversionDisabled() { - final String originalXml = "1234"; - final String expectedJsonString = "{\"root\":{\"id\":{\"xsi:type\":\"java.lang.String\",\"content\":1234}}}"; - final JSONObject expectedJson = new JSONObject(expectedJsonString); - final JSONObject actualJson = XML.toJSONObject(originalXml, new XMLParserConfiguration()); - + String originalXml = "1234"; + String expectedJsonString = "{\"root\":{\"id\":{\"xsi:type\":\"string\",\"content\":1234}}}"; + JSONObject expectedJson = new JSONObject(expectedJsonString); + JSONObject actualJson = XML.toJSONObject(originalXml, new XMLParserConfiguration()); Util.compareActualVsExpectedJsonObjects(actualJson,expectedJson); } @@ -991,12 +993,23 @@ public void testToJsonWithTypeWhenTypeConversionDisabled() { */ @Test public void testToJsonWithTypeWhenTypeConversionEnabled() { - final String originalXml = "1234" - + "1234"; - final String expectedJsonString = "{\"root\":{\"id2\":1234,\"id1\":\"1234\"}}"; - final JSONObject expectedJson = new JSONObject(expectedJsonString); - final JSONObject actualJson = XML.toJSONObject(originalXml, new XMLParserConfiguration(false, - "content", false, true)); + String originalXml = "1234" + + "1234"; + String expectedJsonString = "{\"root\":{\"id2\":1234,\"id1\":\"1234\"}}"; + JSONObject expectedJson = new JSONObject(expectedJsonString); + Map> xsiTypeMap = new HashMap>(); + xsiTypeMap.put("string", new XMLXsiTypeConverter() { + @Override public String convert(final String value) { + return value; + } + }); + xsiTypeMap.put("integer", new XMLXsiTypeConverter() { + @Override public Integer convert(final String value) { + return Integer.valueOf(value); + } + }); + JSONObject actualJson = XML.toJSONObject(originalXml, new XMLParserConfiguration(false, + "content", false, xsiTypeMap)); Util.compareActualVsExpectedJsonObjects(actualJson,expectedJson); }