Java, поле преобразования преобразования в JAXBElement - PullRequest
0 голосов
/ 30 марта 2020

Я пытаюсь выполнить регистрацию 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 и извлечь из него значение?

1 Ответ

1 голос
/ 31 марта 2020

На самом деле я думаю, что ваш 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);
    }
  }
}
...