首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >反射将字段转换为JAXBElement

反射将字段转换为JAXBElement
EN

Stack Overflow用户
提问于 2020-03-30 18:00:19
回答 1查看 272关注 0票数 0

我正在尝试执行SOAPMessage的日志记录。这个对象包含包装类和JAXBElements,我正在执行如下操作

代码语言:javascript
复制
@Before("soapRequest()")
public void logBefore(JoinPoint joinPoint) {

    Object[] signatureArgs = joinPoint.getArgs();
    System.out.println("\n\n\n");
    for (Object signatureArg : signatureArgs) {
        StringBuilder sb = new StringBuilder();

        try {

            Field[] aClassFields = signatureArg.getClass().getDeclaredFields();
            sb.append(signatureArg.getClass().getSimpleName() + " [ ");
            for (Field f : aClassFields) {
                f.setAccessible(true);
                String fName = f.getName();

                String value = "";
                if(f.get(signatureArg) instanceof JAXBElement) {
                    log.info("is instance of");
                    JAXBElement val = (JAXBElement) f.get(signatureArg);
                    log.info(val.toString());
                    value = val.getValue().toString();
                } else {
                    value = f.get(signatureArg).toString();
                }

                sb.append("(" + f.getType() + ") " + fName + " = " + value + ", ");
            }
            sb.append("]");
        } catch (Exception e) {
            e.printStackTrace();
        }

        System.out.println(sb.toString());
    }
}

然而,这一行抛出NPE:

代码语言:javascript
复制
if(f.get(signatureArg) instanceof JAXBElement) {
                        log.info("is instance of");
                        JAXBElement val = (JAXBElement) f.get(signatureArg);
                        log.info(val.toString());
                        value = val.getValue().toString();
                    }

如何检查字段是否是JAXBElement的实例并从中提取值?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-03-31 04:22:05

实际上,我认为您的NPE发生在这一行代码的then块中:

代码语言:javascript
复制
value = f.get(signatureArg).toString();

如果字段值为null,则会发生这种情况,因为在null上不能调用toString()。顺便说一句,这应该发生在任何null字段中,而不仅仅是JAXBElement字段。您不需要toString(),您只需删除它,因为当您打印任何对象时,它将在适用的情况下自动使用它的toString()表示。

在我看来,您的代码也比必需的要复杂得多,对于一些重构和重命名变量,then块根本就不再必要了。下面是我在普通Java + AspectJ (没有Spring)中为您提供的AspectJ:

代码语言:javascript
复制
package de.scrum_master.app;

import javax.xml.bind.JAXBElement;

public class Container {
  private String name;
  private JAXBElement jaxbElement;

  public Container(String name, JAXBElement jaxbElement) {
    this.name = name;
    this.jaxbElement = jaxbElement;
  }
}
代码语言:javascript
复制
package de.scrum_master.app;

import javax.xml.bind.JAXBElement;
import javax.xml.namespace.QName;

public class Application {
  public void doSomething(int number, String text, Container myContainer) {}

  public static void main(String[] args) {
    Application application = new Application();
    application.doSomething(11, "foo", new Container("bar", new JAXBElement(new QName("local"), String.class, "dummy")));
    application.doSomething(11, "foo", new Container("bar", null));
  }
}
代码语言:javascript
复制
package de.scrum_master.aspect;

import java.lang.reflect.Field;

import javax.xml.bind.JAXBElement;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class MyAspect {
  @Pointcut("execution(* doSomething(..))")
  private void soapRequest() {}

  @Before("soapRequest()")
  public void logBefore(JoinPoint joinPoint) {
    System.out.println(joinPoint);

    for (Object methodArg : joinPoint.getArgs()) {
      StringBuilder sb = new StringBuilder();
      try {
        sb.append(methodArg.getClass().getSimpleName() + " [ ");
        for (Field field : methodArg.getClass().getDeclaredFields()) {
          field.setAccessible(true);
          String fieldName = field.getName();
          Object value = field.get(methodArg);
          if (value instanceof JAXBElement) {
            System.out.println("  -> is instance of");
            JAXBElement jaxbElement = (JAXBElement) value;
            System.out.println("  -> " + jaxbElement);
            value = jaxbElement.getValue();
          }
          // Un-comment this in order to see the NPE
          //else {
          //  value = field.get(methodArg).toString();
          //}
          sb.append("(" + field.getType() + ") " + fieldName + " = " + value + ", ");
        }
        sb.append("]");
      } catch (Exception e) {
        e.printStackTrace();
      }
      System.out.println("  " + sb);
    }
  }
}

控制台日志如下所示:

代码语言:javascript
复制
execution(void de.scrum_master.app.Application.doSomething(int, String, Container))
  Integer [ (int) MIN_VALUE = -2147483648, (int) MAX_VALUE = 2147483647, (class java.lang.Class) TYPE = int, (class [C) digits = [C@8efb846, (class [C) DigitTens = [C@2a84aee7, (class [C) DigitOnes = [C@a09ee92, (class [I) sizeTable = [I@30f39991, (int) value = 11, (int) SIZE = 32, (int) BYTES = 4, (long) serialVersionUID = 1360826667806852920, ]
  String [ (class [C) value = [C@4a574795, (int) hash = 0, (long) serialVersionUID = -6849794470754667710, (class [Ljava.io.ObjectStreamField;) serialPersistentFields = [Ljava.io.ObjectStreamField;@f6f4d33, (interface java.util.Comparator) CASE_INSENSITIVE_ORDER = java.lang.String$CaseInsensitiveComparator@23fc625e, ]
  -> is instance of
  -> javax.xml.bind.JAXBElement@4f023edb
  Container [ (class java.lang.String) name = bar, (class javax.xml.bind.JAXBElement) jaxbElement = dummy, ]
execution(void de.scrum_master.app.Application.doSomething(int, String, Container))
  Integer [ (int) MIN_VALUE = -2147483648, (int) MAX_VALUE = 2147483647, (class java.lang.Class) TYPE = int, (class [C) digits = [C@8efb846, (class [C) DigitTens = [C@2a84aee7, (class [C) DigitOnes = [C@a09ee92, (class [I) sizeTable = [I@30f39991, (int) value = 11, (int) SIZE = 32, (int) BYTES = 4, (long) serialVersionUID = 1360826667806852920, ]
  String [ (class [C) value = [C@4a574795, (int) hash = 0, (long) serialVersionUID = -6849794470754667710, (class [Ljava.io.ObjectStreamField;) serialPersistentFields = [Ljava.io.ObjectStreamField;@f6f4d33, (interface java.util.Comparator) CASE_INSENSITIVE_ORDER = java.lang.String$CaseInsensitiveComparator@23fc625e, ]
  Container [ (class java.lang.String) name = bar, (class javax.xml.bind.JAXBElement) jaxbElement = null, ]

看见?你的错误已经消失了。注释else块以查看它的重新出现,然后从行中删除.toString(),它就会再次消失。也许它能帮助你更好地理解你的错误。

顺便说一下,我觉得日志输出看起来有点难看。您还注意到您也打印了静态字段吗?你应该把它们过滤掉。但是我不想修改你的代码,因为我仍然希望你能识别它。

您的方面的简短版本不需要为JAXBElement进行额外的调试日志记录,也不需要使用try - catch,而是声明了一个异常:

代码语言:javascript
复制
package de.scrum_master.aspect;

import java.lang.reflect.Field;

import javax.xml.bind.JAXBElement;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class MyAspect {
  @Pointcut("execution(* doSomething(..))")
  private void soapRequest() {}

  @Before("soapRequest()")
  public void logBefore(JoinPoint joinPoint) throws Throwable {
    System.out.println(joinPoint);
    for (Object methodArg : joinPoint.getArgs()) {
      StringBuilder sb = new StringBuilder();
      sb.append(methodArg.getClass().getSimpleName() + " [ ");
      for (Field field : methodArg.getClass().getDeclaredFields()) {
        field.setAccessible(true);
        String fieldName = field.getName();
        Object value = field.get(methodArg);
        if (value instanceof JAXBElement)
          value = ((JAXBElement) value).getValue();
        sb.append("(" + field.getType() + ") " + fieldName + " = " + value + ", ");
      }
      sb.append("]");
      System.out.println("  " + sb);
    }
  }
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/60936635

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档