Soap Java,反射将字段转换为JAXBElement

Soap Java,反射将字段转换为JAXBElement,soap,reflection,aspectj,spring-aop,Soap,Reflection,Aspectj,Spring Aop,我正在尝试执行SOAPMessage的日志记录。 这个对象包含包装器类和JAXBElements,我正在做类似的事情 @Before("soapRequest()") public void logBefore(JoinPoint joinPoint) { Object[] signatureArgs = joinPoint.getArgs(); System.out.println("\n\n\n"); for (Object signatureArg : signa

我正在尝试执行SOAPMessage的日志记录。 这个对象包含包装器类和JAXBElements,我正在做类似的事情

@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:

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的实例并从中提取值?

实际上,我认为您的NPE出现在这行代码的then块中:

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

在我看来,您的代码也比需要的复杂得多,通过一些重构和重命名变量,then块就不再需要了。下面是我在纯Java+AspectJ中为您准备的无Spring版本:

包de.scrum_master.app; 导入javax.xml.bind.JAXBElement; 公营货柜{ 私有字符串名称; 私有的JAXBElement JAXBElement; 公共容器字符串名称,JAXBElement JAXBElement{ this.name=名称; this.jaxbElement=jaxbElement; } } 包de.scrum_master.app; 导入javax.xml.bind.JAXBElement; 导入javax.xml.namespace.QName; 公共类应用程序{ public void doSomethingint编号、字符串文本、容器myContainer{} 公共静态无效字符串[]args{ 应用程序=新应用程序; application.doSomething11、foo、新Containerbar、新JAXBElementnew QNamelocal、String.class、dummy; application.doSomething11,foo,新容器栏,null; } } 包de.scrum_master.aspect; 导入java.lang.reflect.Field; 导入javax.xml.bind.JAXBElement; 导入org.aspectj.lang.JoinPoint; 导入org.aspectj.lang.annotation.Aspect; 导入org.aspectj.lang.annotation.Before; 导入org.aspectj.lang.annotation.Pointcut; @面貌 公共类MyAspect{ @Pointcutexecution*doSomething。。 私有无效soapRequest{} @请求之前 连接点之前的公共无效日志连接点{ System.out.printlnjoinPoint; 对于对象方法arg:joinPoint.getArgs{ StringBuilder sb=新的StringBuilder; 试一试{ sb.appendmethodArg.getClass.getSimpleName+[; 对于字段字段:methodArg.getClass.getDeclaredFields{ field.setAccessibletrue; 字符串fieldName=field.getName; 对象值=field.getmethodArg; JAXBELENT的if值实例{ System.out.println->是的实例; JAXBElement JAXBElement=JAXBElement值; System.out.println->+jaxbElement; value=jaxbElement.getValue; } //联合国对此发表评论,以查看NPE //否则{ //value=field.getmethodArg.toString; //} sb.append+field.getType++fieldName+=+value+; } [某人]; }捕获异常e{ e、 打印跟踪; } System.out.println+sb; } } } 控制台日志如下所示:

executionvoid de.scrum\u master.app.Application.doSomethingint,字符串,容器 整数[int MIN_VALUE=-2147483648,int MAX_VALUE=2147483647,class java.lang.class TYPE=int,class[C位=[C@8efb846,类别[C数字=[C@2a84aee7,类别[C]洋地黄酮=[C@a09ee92,类别[I大小表=[I@30f39991,int-value=11,int-SIZE=32,int-BYTES=4,long-serialVersionUID=1360826667806852920,] 字符串[类[C值=[C@4a574795,int hash=0,long serialVersionUID=-6849794470754667710,类[Ljava.io.ObjectStreamField;serialPersistentFields=[Ljava.io.ObjectStreamField;@f6f4d33,接口java.util.Comparator不区分大小写\u顺序=java.lang.String$CaseInsensitiveComparator@23fc625e, ] ->例如 ->javax.xml.bind。JAXBElement@4f023edb 容器[class java.lang.String name=bar,class javax.xml.bind.JAXBElement JAXBElement=dummy,] executionvoid de.scrum\u master.app.Application.doSomethingint,字符串,容器 整数[int MIN_VALUE=-2147483648,int MAX_VALUE=2147483647,class java.lang.class TYPE=int,class[C位=[C@8efb846,类别[C数字=[C@2a84aee7,类别[C]洋地黄酮=[C@a09ee92,类别[I大小表=[I@30f39991,int-value=11,int-SIZE=32,int-BYTES=4,long-serialVersionUID=1360826667806852920,] 字符串[类[C值=[C@4a574795,int hash=0,long serialVersionUID=-6849794470754667710,类[Ljava.io.ObjectStreamField;serialPersistentFields=[Ljava.io.ObjectStreamField;@f6f4d33,接口java.util.Comparator不区分大小写\u顺序=java.lang.String$CaseInsensitiveComparator@23fc625e, ] 容器[class java.lang.String name=bar,class javax.xml.bind.JAXBElement JAXBElement=null,] 看到了吗?您的错误已经消失了。请取消对else块的注释,以便看到它重新出现,然后从行中删除.toString并继续 他又走了。也许它能帮助你更好地理解你的错误

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

aspect的简短版本没有额外的JAXBElement调试日志记录,也没有try-catch,但是声明的异常是:

包de.scrum_master.aspect; 导入java.lang.reflect.Field; 导入javax.xml.bind.JAXBElement; 导入org.aspectj.lang.JoinPoint; 导入org.aspectj.lang.annotation.Aspect; 导入org.aspectj.lang.annotation.Before; 导入org.aspectj.lang.annotation.Pointcut; @面貌 公共类MyAspect{ @Pointcutexecution*doSomething。。 私有无效soapRequest{} @请求之前 public void logBeforeJoinPoint joinPoint抛出可丢弃{ System.out.printlnjoinPoint; 对于对象方法arg:joinPoint.getArgs{ StringBuilder sb=新的StringBuilder; sb.appendmethodArg.getClass.getSimpleName+[; 对于字段字段:methodArg.getClass.getDeclaredFields{ field.setAccessibletrue; 字符串fieldName=field.getName; 对象值=field.getmethodArg; JAXBELENT的if值实例 value=JAXBElement value.getValue; sb.append+field.getType++fieldName+=+value+; } [某人]; System.out.println+sb; } } }
Mateusz,您多年来一直是SO会员,拥有500+积分的良好声誉。我认为你应该知道什么是A,以及如何写出能得到好答案的问题。帮助您的助手提供不仅仅是片段的帮助。没有人可以编译和运行您的代码。甚至方面都不完整,缺少切入点。我相信添加它和一个生成方面应该拦截的值的示例类会有所帮助。还有一个想法:你非常专注于技术上想做什么,但是没有足够的信息让任何人理解你想要实现什么以及为什么。这就是所谓的。也许一些上下文信息会有帮助,激励他人和自己也考虑其他解决方案。由于大量使用反射,这一个看起来非常做作,并且可能很慢。这只是调试/跟踪方面,还是在生产环境中使用?AOP不会替换调试器。您也没有提供堆栈跟踪。你说:这一行抛出NPE,然后引用5行代码。谢谢kriegaex。事实上,正如你所说的toString方法。有些肥皂片是空的,当我打电话给toString时,我得到了NPE。