-
Notifications
You must be signed in to change notification settings - Fork 2.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Added type conversion support #540
Conversation
bba8246
to
e828c11
Compare
Sounds like you are trying to make the case that Java-specific XML xsi:type strings should be supported. If so, is this commonly used by projects other than yours? Otherwise, no real objection since we allow a bit more latitude for supporting XML to JSON transformations, which will always be imperfect. We already have too many fixed parameters for XMLParserConfiguration. This needs to be fixed first. The existing constructors need to be deprecated, the properties made non-final, and setters added to set up the config manually. I will add an issue to address this. |
@kumar529 would it make sense to have mappings for i.e. /**
Interface to support conversions of XML xsl:type values to Java objects
*/
public interface XMLXsiTypeConverter<T> {
public T convert(String value);
}
public void someFunc() {
Map<string, XsiTypeConverter<?>> XsiTypeMap = new HashMap<>();
XsiTypeMap.put("string", new XMLXsiTypeConverter<String>(){ public String convert(String value){return value;}});
XsiTypeMap.put("int", new XMLXsiTypeConverter<Long>(){ public Long convert(String value){return Long.valueOf(value);}});
XsiTypeMap.put("bool", new XMLXsiTypeConverter<Long>(){ public Boolean convert(String value){return Boolean.FALSE;}});
XMLParserConfiguration config = new XMLParserConfiguration(false, "content", true, XsiTypeMap);
JSONObject jo = XML.toJSONObject(myInput, config);
} |
Sorry, ignore, thought that question was addressed to me. |
@johnjaylward I think HashMap will not serve the purpose. @stleary I am facing the problem of data conversion. Currently, the lib supports two types of config for data conversion:
So I want to add type support on specific elements. For example: Here the value for id1 will be converted to a string, id2 will be converted to an integer, id3 has no type information so default behavior will be applicable. We can do without adding any configuration change. If xsi:type is present, it will try to convert only. @stleary Please suggest what is your opinion. We can also use "string", "number", "boolean" for type representation and we can handle these cases from code. |
@kumar529, that was why I suggested the hash map. The hashmap is to map the xsi:type to the java type. The xsi:type would then be configurable per application. You don't need to pick how the type is represented in the xml now. Instead configure it at runtime with converters. I don't think we should presume that all providers of XML will have the same xsi:type schema, nor that all consumers will want conversions done the same way. |
>>>If the value is an integer in XML, it will convert it to an integer in JSON. So sometimes the conversion changes the values. Can it be confirmed that this is not a regression introduced in #453 or one of the subsequent BigNumber/Decimal/Integer commits? |
@johnjaylward Yes, HashMap can work. The client will provide the HashMap at the time of initialization. |
@kumar529 This PR has several issues -
|
@stleary I think the "changing values" is due to not using the "keep strings" option (default parsing). The XSI processing as proposed here would basically be another flavor of "keep strings" but lets generators of XML specify the actual types instead of the tokener always using a string value. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See conversation comments.
@stleary Sure, I will make the change. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add a test case in that tests an XML structure that looks something like this:
<root>
<asString xsi:type="string">12345</asString>
<asInt>54321</asInt>
</root>
I would expect a resulting JSON that looks similar to this:
{
"asString":"12345",
"asInt":54321
}
this.keepStrings = keepStrings; | ||
this.cDataTagName = cDataTagName; | ||
this.convertNilAttributeToNull = false; | ||
this(keepStrings, cDataTagName, false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please do not modify deprecated functions, or use them in your tests.
/** | ||
* This will allow type conversion for values in XML if xsi:type attribute is defined | ||
*/ | ||
public Map<String, XMLXsiTypeConverter<?>> xsiTypeMap; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, I finally had time for a closer look at the configuration changes. With the new changes in #543, this should be private with a Getter and no Setter. Preferably the getter should return an "Unmodifiable Map". To prevent wrapping the collection every time the getter is called, storing the unmodifiable map in this variable would be acceptable.
Note in the Getter javadoc that the map is "unmodifiable"
* xsi:type="integer" as integer, xsi:type="string" as string | ||
* <code>null</code> to use default behaviour. | ||
*/ | ||
public XMLParserConfiguration (final boolean keepStrings, final String cDataTagName, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can be marked private instead of public.
Also, please change:
this.xsiTypeMap = xsiTypeMap
to:
this.xsiTypeMap = Collections.unmodifiableMap(new HashMap<String, XMLXsiTypeConverter<?>>(xsiTypeMap));
Our expected configuration should look something like this:
XMLParserConfiguration xmlConfig = new XMLParserConfiguration().withKeepStrings(false).WithXsiTypeMap(myXsiMap);
// use the config
After marking this private, also update the "clone" method (currently line 165). Be sure to follow the comment that is included in the "clone" method. If changing the constructor above to do the shallow clone/unmodifiable map wrapping, you can probably just update the clone to call this private constructor.
Lastly, be sure to create the new "with" method that will take the XSI:Type conversion map.
Manual gradlew build is failing due to javadoc problems, please fix. @johnjaylward Do you have any more un-addressed issues? |
I do not see this test case in the change set. The XML I see tested is: <root><asString xsi:type="string">12345</asString><asInt xsi:type="integer">54321</asInt></root> NOT <root><asString xsi:type="string">12345</asString><asInt>54321</asInt></root> |
@stleary @johnjaylward Please let me know if there is anything pending in this PR. |
@kumar529, I believe that my concerns have been addressed. Sorry I did not notice your most recent commit until you commented. |
What problem does this code solve? Risks Changes to the API? Will this require a new release? Should the documentation be updated? Does it break the unit tests? Was any code refactored in this commit? Review status |
The lib doesn't support type conversion for a specific value.
I have added the feature to support type conversion for a specific tag.
Example:
//XML String
<root><id1 xsi:type="java.lang.String">1234</id1><id2 xsi:type="java.lang.Integer">1234</id2></root>
//Corresponding JSON String
{"root":{"id2":1234,"id1":"1234"}}