• GSON -JSON 反序列化-多节点名称支持


    引言.最近对接支付宝支付时,发现支付宝接口返回一个泛型的对象.如{"XXX_YYY_response":{},"sign":"AFDSS#QR@43211423142341FAF"},其中 XXX_YYY_response 是动态变化的,即多个值映射到泛型字段.
    GSON 提供了 @SerializeName注解来实现.
     1 @Retention(RetentionPolicy.RUNTIME)
     2 @Target({ElementType.FIELD, ElementType.METHOD})
     3 public @interface SerializedName {
     4  
     5 /**
     6 * @return the desired name of the field when it is serialized or deserialized
     7 */
     8 String value();
     9 /**
    10 * @return the alternative names of the field when it is deserialized
    11 */
    12 String[] alternate() default {};
    13 }
     
    可以给 alternate 赋一个数组来实现.但是每次引入新的支付宝接口时,要变更注解字段 alternate (不能使用变量,因注解字段值必须是常量)的值.不符合开闭原则.
     
    使用反射来解决.给泛型对象添加静态注册名字方法,动态改变注解alternate 的值.在具体对象反序化前可以注册一次.
     1 public class AlipayResult<OutParameter extends AlipayBasicOutParameter> {
     2  
     3 private static final Logger LOG= LoggerFactory.getLogger(AlipayResult.class);
     4  
     5 @Expose
     6 private String sign;
     7 private static final String SIGN_TITLE_TAG="sign";
     8  
     9 @Expose
    10 @SerializedName(value="",alternate = {})
    11 private OutParameter outParameter;
    12  
    13  
    14 @Expose
    15 @SerializedName("error_response")
    16 private AlipayError errorObject;
    17  
    18  
    19 private static final Set<String> JSON_NAMES= new HashSet<>();
    20  
    21 static {
    22 JSON_NAMES.add("error_response");
    23 }
    24  
    25  
    26  
    27 public static synchronized final void registerOutParameterAlternate(final String namespace){
    28 try {
    29 JSON_NAMES.add(namespace);
    30 Field field = AlipayResult.class.getDeclaredField("outParameter");
    31 field.setAccessible(true);
    32 SerializedName serialName = field.getDeclaredAnnotation(SerializedName.class);
    33 String[] ns = serialName.alternate();
    34 for (String item : ns) {
    35 if (item.equals(namespace)) {
    36 return;
    37 }
    38 }
    39 InvocationHandler h = Proxy.getInvocationHandler(serialName);
    40 // 获取 AnnotationInvocationHandler 的 memberValues 字段
    41 Field hField = h.getClass().getDeclaredField("memberValues");
    42 // 因为这个字段事 private final 修饰,所以要打开权限
    43 hField.setAccessible(true);
    44 // 获取 memberValues
    45 Map memberValues = (Map) hField.get(h);
    46 // 修改 value 属性值
    47 List<String> target =new ArrayList<String>();
    48 if(null!=ns&&ns.length>0){
    49 for (String i:ns){
    50 target.add(i);
    51 }
    52 }
    53 target.add(namespace);
    54 String[] alternateArr = target.toArray(new String[0]);
    55 memberValues.put("alternate", alternateArr);
    56 if (LOG.isInfoEnabled()) {
    57 LOG.info("alternate value is " + alternateArr);
    58 }
    59 }catch (Throwable throwable){
    60 throw new RuntimeException(throwable);
    61 }
    62 }
    63  
    64 private static final String AlipayResponseNameSpaces="";
    65  
    66 public String getSign() {
    67 return sign;
    68 }
    69  
    70 public void setSign(String sign) {
    71 this.sign = sign;
    72 }
    73  
    74 public OutParameter getOutParameter() {
    75 return outParameter;
    76 }
    77  
    78 public void setOutParameter(OutParameter outParameter) {
    79 this.outParameter = outParameter;
    80 }
     
  • 相关阅读:
    asp.net与javascript问题
    动态加载用户控件
    ASP.NET中实现模版的动态加载
    一个简单的购物车
    给图片加上水印效果
    用存储过程自定义分页
    上传图片及显示图片
    sql server图片的保存和读取
    Legato Single Server SertupFor RMAN
    确定裸设备上控制文件的大小
  • 原文地址:https://www.cnblogs.com/hhbk/p/7814731.html
Copyright © 2020-2023  润新知