Java,反射将字段转换为 JAXBElement
Java, reflection convert field into JAXBElement
我正在尝试执行 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
代码块的这行代码中:
value = f.get(signatureArg).toString();
如果字段值为 null
,则会发生这种情况,因为在 null
上您无法调用 toString()
。顺便说一句,这应该发生在任何 null
字段上,而不仅仅是 JAXBElement
。你不需要 toString()
,你可以删除它,因为当你打印任何对象时,它会在适用的地方自动使用它的 toString()
表示。
在我看来,您的代码也比必要的更复杂,并且通过一些重组和重命名变量,根本不再需要 then
块。这是我的 MCVE 纯 Java + AspectJ(没有 Spring)给你的:
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;
}
}
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));
}
}
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);
}
}
}
控制台日志如下所示:
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
但声明的异常的简短版本将是:
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);
}
}
}
我正在尝试执行 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
代码块的这行代码中:
value = f.get(signatureArg).toString();
如果字段值为 null
,则会发生这种情况,因为在 null
上您无法调用 toString()
。顺便说一句,这应该发生在任何 null
字段上,而不仅仅是 JAXBElement
。你不需要 toString()
,你可以删除它,因为当你打印任何对象时,它会在适用的地方自动使用它的 toString()
表示。
在我看来,您的代码也比必要的更复杂,并且通过一些重组和重命名变量,根本不再需要 then
块。这是我的 MCVE 纯 Java + AspectJ(没有 Spring)给你的:
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;
}
}
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));
}
}
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);
}
}
}
控制台日志如下所示:
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
但声明的异常的简短版本将是:
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);
}
}
}