From 30182e13e7b294b8a0771e47a84b0ed45a628a1f Mon Sep 17 00:00:00 2001 From: Mike Eltsufin Date: Tue, 14 Mar 2023 03:19:41 +0000 Subject: [PATCH] fix: JSON deserialization setter case priority (#1831) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: JSON deserialization setter case priority Fixes the problem of JSON deserialization ignoring the case of setters. Now case-sensitive setter method matches are considered first. Fixes: #1830. * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md --------- Co-authored-by: Owl Bot --- .../com/google/api/client/util/FieldInfo.java | 32 ++++++++++-------- .../google/api/client/util/FieldInfoTest.java | 33 +++++++++++++++++++ 2 files changed, 52 insertions(+), 13 deletions(-) diff --git a/google-http-client/src/main/java/com/google/api/client/util/FieldInfo.java b/google-http-client/src/main/java/com/google/api/client/util/FieldInfo.java index 3830a8664..36d0dc9dc 100644 --- a/google-http-client/src/main/java/com/google/api/client/util/FieldInfo.java +++ b/google-http-client/src/main/java/com/google/api/client/util/FieldInfo.java @@ -134,12 +134,20 @@ public static FieldInfo of(Field field) { } /** Creates list of setter methods for a field only in declaring class. */ - private Method[] settersMethodForField(Field field) { + private Method[] settersMethodForField(final Field field) { List methods = new ArrayList<>(); + String fieldSetter = "set" + Ascii.toUpperCase(field.getName().substring(0, 1)); + if (field.getName().length() > 1) { + fieldSetter += field.getName().substring(1); + } for (Method method : field.getDeclaringClass().getDeclaredMethods()) { - if (Ascii.toLowerCase(method.getName()).equals("set" + Ascii.toLowerCase(field.getName())) - && method.getParameterTypes().length == 1) { - methods.add(method); + if (method.getParameterTypes().length == 1) { + // add case-sensitive matches first in the list + if (method.getName().equals(fieldSetter)) { + methods.add(0, method); + } else if (Ascii.toLowerCase(method.getName()).equals(Ascii.toLowerCase(fieldSetter))) { + methods.add(method); + } } } return methods.toArray(new Method[0]); @@ -216,15 +224,13 @@ public Object getValue(Object obj) { * value. */ public void setValue(Object obj, Object value) { - if (setters.length > 0) { - for (Method method : setters) { - if (value == null || method.getParameterTypes()[0].isAssignableFrom(value.getClass())) { - try { - method.invoke(obj, value); - return; - } catch (IllegalAccessException | InvocationTargetException e) { - // try to set field directly - } + for (Method method : setters) { + if (value == null || method.getParameterTypes()[0].isAssignableFrom(value.getClass())) { + try { + method.invoke(obj, value); + return; + } catch (IllegalAccessException | InvocationTargetException e) { + // try to set field directly } } } diff --git a/google-http-client/src/test/java/com/google/api/client/util/FieldInfoTest.java b/google-http-client/src/test/java/com/google/api/client/util/FieldInfoTest.java index c000a90dd..0cd1c17de 100644 --- a/google-http-client/src/test/java/com/google/api/client/util/FieldInfoTest.java +++ b/google-http-client/src/test/java/com/google/api/client/util/FieldInfoTest.java @@ -14,6 +14,7 @@ package com.google.api.client.util; +import com.google.api.client.json.GenericJson; import junit.framework.TestCase; /** @@ -49,4 +50,36 @@ public void testEnumValue() { assertEquals(E.OTHER_VALUE, FieldInfo.of(E.OTHER_VALUE).enumValue()); assertEquals(E.NULL, FieldInfo.of(E.NULL).enumValue()); } + + public static final class Data extends GenericJson { + @Key String passcode; + @Key String passCode; + + public Data setPasscode(String passcode) { + this.passcode = passcode; + return this; + } + + public Data setPassCode(String passCode) { + this.passCode = passCode; + return this; + } + } + + public void testSetValueCaseSensitivityPriority() { + Data data = new Data(); + data.setPasscode("pass1"); + data.setPassCode("pass2"); + data.set("passCode", "passX"); + + assertEquals(data.passcode, "pass1"); + assertEquals(data.passCode, "passX"); + + data.setPasscode("pass1"); + data.setPassCode("pass2"); + data.set("passcode", "passX"); + + assertEquals(data.passcode, "passX"); + assertEquals(data.passCode, "pass2"); + } }