diff --git a/java/code/src/com/redhat/rhn/frontend/xmlrpc/BaseHandler.java b/java/code/src/com/redhat/rhn/frontend/xmlrpc/BaseHandler.java
index 701621e8fc3e..51ac7b4473f4 100644
--- a/java/code/src/com/redhat/rhn/frontend/xmlrpc/BaseHandler.java
+++ b/java/code/src/com/redhat/rhn/frontend/xmlrpc/BaseHandler.java
@@ -42,6 +42,9 @@
import com.suse.manager.api.ReadOnly;
import com.suse.salt.netapi.utils.Xor;
+import com.google.gson.Gson;
+import com.google.gson.JsonSyntaxException;
+
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.hibernate.HibernateException;
@@ -409,6 +412,37 @@ public static void ensureUserRole(User user, Role role)
}
}
+ /**
+ * Parse an input element uniformly for both XMLRPC and JSON APIs.
+ *
+ * Useful when parsing input parameter values inside complex structs where there's no type information available.
+ *
+ * XMLRPC and JSON APIs automatically parse the values for top-level parameters according to the type information
+ * available. However, the values nested inside a complex struct must be parsed inside the specific handler method.
+ *
+ * @param argIn the input value
+ * @return the parsed {@link T} object
+ * @throws InvalidParameterException when the input cannot be parsed
+ */
+ protected static T parseInputValue(Object argIn, Class typeIn) throws InvalidParameterException {
+ T value;
+ try {
+ if (typeIn.isAssignableFrom(argIn.getClass())) {
+ // Assume exact type (XMLRPC)
+ value = typeIn.cast(argIn);
+ }
+ else {
+ // Interpret as string (JSON over HTTP)
+ value = new Gson().fromJson("\"" + argIn + "\"", typeIn);
+ }
+ }
+ catch (ClassCastException | JsonSyntaxException e) {
+ throw new InvalidParameterException("Wrong input format", e);
+ }
+
+ return value;
+ }
+
/**
* Ensure the org exists
* @param orgId the org id to check
diff --git a/java/code/src/com/redhat/rhn/frontend/xmlrpc/channel/software/ChannelSoftwareHandler.java b/java/code/src/com/redhat/rhn/frontend/xmlrpc/channel/software/ChannelSoftwareHandler.java
index bb2d4003dc30..a677c162e1bd 100644
--- a/java/code/src/com/redhat/rhn/frontend/xmlrpc/channel/software/ChannelSoftwareHandler.java
+++ b/java/code/src/com/redhat/rhn/frontend/xmlrpc/channel/software/ChannelSoftwareHandler.java
@@ -1516,7 +1516,7 @@ public List listErrata(User loggedInUser,
@ReadOnly
public List listErrata(User loggedInUser, String channelLabel)
throws NoSuchChannelException {
- return listErrata(loggedInUser, channelLabel, (Date) null);
+ return listErrata(loggedInUser, channelLabel, null);
}
/**
diff --git a/java/code/src/com/redhat/rhn/frontend/xmlrpc/errata/ErrataHandler.java b/java/code/src/com/redhat/rhn/frontend/xmlrpc/errata/ErrataHandler.java
index 4a6852036160..763fba2562dc 100644
--- a/java/code/src/com/redhat/rhn/frontend/xmlrpc/errata/ErrataHandler.java
+++ b/java/code/src/com/redhat/rhn/frontend/xmlrpc/errata/ErrataHandler.java
@@ -279,37 +279,19 @@ public Integer setDetails(User loggedInUser, String advisoryName, Map details = new HashMap<>();
+ Date expectedDate = Date.from(LocalDate.of(1989, 4, 1).atStartOfDay().toInstant(ZoneOffset.UTC));
+ // Set using Date instance (XMLRPC)
+ details.put("issue_date", expectedDate);
+ // Set using ISO-8601 String (JSON over HTTP)
+ details.put("update_date", "1989-04-01T00:00:00Z");
+
+ int result = handler.setDetails(user, errata.getAdvisoryName(), details);
+
+ assertEquals(1, result);
+
+ Errata updatedErrata = ErrataManager.lookupErrata(errata.getId(), user);
+ assertEquals(expectedDate, updatedErrata.getIssueDate());
+ assertEquals(expectedDate, updatedErrata.getUpdateDate());
+ }
+
@Test
public void testListAffectedSystems() throws Exception {
//no affected systems
diff --git a/java/code/src/com/redhat/rhn/frontend/xmlrpc/system/provisioning/snapshot/SnapshotHandler.java b/java/code/src/com/redhat/rhn/frontend/xmlrpc/system/provisioning/snapshot/SnapshotHandler.java
index 487f9707159d..336e0e27306b 100644
--- a/java/code/src/com/redhat/rhn/frontend/xmlrpc/system/provisioning/snapshot/SnapshotHandler.java
+++ b/java/code/src/com/redhat/rhn/frontend/xmlrpc/system/provisioning/snapshot/SnapshotHandler.java
@@ -290,10 +290,10 @@ public int deleteSnapshots(User loggedInUser, Map dateDetails) {
Date endDate = null;
if (dateDetails.containsKey("startDate")) {
- startDate = (Date)dateDetails.get("startDate");
+ startDate = parseInputValue(dateDetails.get("startDate"), Date.class);
}
if (dateDetails.containsKey("endDate")) {
- endDate = (Date)dateDetails.get("endDate");
+ endDate = parseInputValue(dateDetails.get("endDate"), Date.class);
}
return deleteSnapshots(loggedInUser, startDate, endDate);
}
diff --git a/java/code/src/com/suse/manager/api/ApiRequestParser.java b/java/code/src/com/suse/manager/api/ApiRequestParser.java
index 867680eba96f..dbb29102824a 100644
--- a/java/code/src/com/suse/manager/api/ApiRequestParser.java
+++ b/java/code/src/com/suse/manager/api/ApiRequestParser.java
@@ -31,7 +31,6 @@
*/
public class ApiRequestParser {
private final Gson gson;
- private final JsonParser parser = new JsonParser();
/**
* Constructs a parser with a {@link Gson} instance
@@ -49,7 +48,7 @@ public ApiRequestParser(Gson gsonIn) {
* @return the JSON object properties as key-value pairs
*/
public Map parseBody(String body) throws ParseException {
- JsonElement bodyElement = parser.parse(body);
+ JsonElement bodyElement = JsonParser.parseString(body);
if (bodyElement.isJsonNull()) {
return Collections.emptyMap();
@@ -115,11 +114,11 @@ private JsonElement parseQueryParam(String value) throws ParseException {
JsonElement element;
try {
// Try to parse the literal value
- element = parser.parse(value);
+ element = JsonParser.parseString(value);
}
catch (JsonSyntaxException e) {
// Invalid syntax, try as string
- element = parser.parse('"' + value + '"');
+ element = JsonParser.parseString('"' + value + '"');
}
if (element.isJsonPrimitive() || element.isJsonNull()) {
diff --git a/java/code/src/com/suse/manager/api/ListDeserializer.java b/java/code/src/com/suse/manager/api/ListDeserializer.java
index f3c89d64b26f..a8797132e628 100644
--- a/java/code/src/com/suse/manager/api/ListDeserializer.java
+++ b/java/code/src/com/suse/manager/api/ListDeserializer.java
@@ -28,9 +28,7 @@
/**
* Custom {@link List} deserializer that handles arbitrary numbers properly
- * @deprecated the same behavior can be achieved using ToNumberPolicy.LONG_OR_DOUBLE with gson-2.8.9
*/
-@Deprecated
public class ListDeserializer implements JsonDeserializer> {
@Override
public List