На самом деле я думаю, что ваш NPE встречается в блоке then
в этой строке кода:
value = f.get(signatureArg).toString();
Это происходит, если значение поля равно null
, потому что на null
вы не можете вызвать toString()
. Кстати, это должно происходить для любого поля null
, а не только для JAXBElement
. Вам не нужно toString()
, вы можете просто удалить его, потому что при печати любого объекта он автоматически будет использовать его представление toString()
, где это применимо.
По моему мнению, ваш код также сложнее, чем необходимо, и с некоторыми переменными реструктуризации и переименования блок then
больше не нужен вообще. Вот мой MCVE в обычном виде Java + AspectJ (без пружины) для вас:
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()
из строки, и он снова исчезнет. Может быть, это поможет вам лучше понять вашу ошибку.
Кстати, я думаю, что вывод журнала выглядит довольно некрасиво. Вы также заметили, что вы также печатаете поля stati c? Вы, вероятно, должны отфильтровать их. Но я не хотел больше менять ваш код, потому что я все еще хочу, чтобы вы его распознали.
Короткая версия вашего аспекта без дополнительной отладки для 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);
}
}
}