[JAVA] So lassen Sie zu, dass Anmerkungen Elemente festlegen, die Sie nicht ausgeben möchten, wenn Sie ein Objekt rekursiv als Zeichenfolge serialisieren

Möglicherweise möchten Sie den Inhalt eines Objekts in einer Zeichenfolge kombinieren und in ein Protokoll ausgeben. Zu diesem Zeitpunkt möchte ich dieses Feld nicht protokollieren! Gibt es so etwas? Es ist ein bisschen nervig, toString () zu implementieren, nicht wahr?

Was du machen willst

Inhalt des Objekts

Cart.java


package jp.co.pmtech.iwata;

public class Cart {
    /**Warenkorb-ID*/
    private int id;
    /**Artikel im Warenkorb*/
    private List<Syohin> syohinList;

    //Getter oder Setter
}

Syohin.java


package jp.co.pmtech.iwata;

public class Syohin {
    /**Produkt ID*/
    private int id;
    /**Produktname*/
    private String name;
    /**Preis*/
    private BigDecimal price;

    //Getter oder Setter
}

App.java


public final class App {
    public static void main(String[] args) {
        Syohin syohin1 = new Syohin();
        syohin1.setId(1);
        syohin1.setName("Kugelschreiber");
        syohin1.setPrice(new BigDecimal(120));

        Syohin syohin2 = new Syohin();
        syohin2.setId(2);
        syohin2.setName("Gewebe");
        syohin2.setPrice(new BigDecimal(298));

        List<Syohin> list = new ArrayList<>();
        list.add(syohin1);
        list.add(syohin2);

        Cart cart = new Cart();
        cart.setId(1);
        cart.setSyohinList(list);
    }
}

Versuchen Sie zu implementieren

Dies kann durch Implementierung wie folgt erreicht werden.

  1. Erstellen Sie eine Anmerkungsklasse für Felder, die nicht stringifiziert sind.
  2. Kommentieren Sie das Zielfeld.
  3. Erweitern Sie ReflectionToStringBuilder, um kommentierte Felder zu ignorieren.
  4. Erweitern Sie ToStringStyle, um rekursiv zu stringifizieren.

Übrigens hat RecursiveToStringStyle von commons-lang3.2 zugenommen, und Sie können es verwenden, um es rekursiv in eine Zeichenfolge zu konvertieren. Da ReflectionToStringBuilder jedoch intern aufgerufen wird, kann das auszugebende Feld nicht gesteuert werden. Aus diesem Grund habe ich mich entschlossen, ToStringStyle dieses Mal selbst zu erweitern. (Details zu RecursiveToStringStyle werden später im Bonus-Teil beschrieben.)

Anmerkungsklasse erstellen

LogIgnore.java


@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LogIgnore {
}

Anmerkung

Dieses Mal werde ich versuchen, den Preis des Produkts nicht anzugeben (Syohin # Preis).

Syohin.java


public class Syohin {
    /**Produkt ID*/
    private int id;
    /**Produktname*/
    private String name;
    /**Preis*/
    @LogIgnore
    private BigDecimal price;
}

ReflectionToStringBuilder-Erweiterung

Es scheint, dass ReflectionToStringBuilder # accept () das zu stringifizierende Feld bestimmt. Überschreiben Sie dies also.

LoggingToStringBuilder.java


public class LoggingToStringBuilder extends ReflectionToStringBuilder {

    public LoggingToStringBuilder(final Object object, final ToStringStyle style) {
        super(object, style);
    }

    public static String reflectionToString(final Object object, final ToStringStyle style) {
        LoggingToStringBuilder builder = new LoggingToStringBuilder(object, style) {
            @Override
            protected boolean accept(final Field field) {
                if (!super.accept(field)) {
                    return false;
                }
                if (field.getAnnotation(LogIgnore.class) != null) {
                    return false;
                }
                return true;
            }
        };

        return builder.toString();
    }
}

Erweiterung von ToStringStyle

Vor commons-lang3.2 haben Sie es anscheinend selbst gemacht.

Erstellen Sie eine Klasse, die ToStringStyle erweitert, indem Sie auf den folgenden Artikel verweisen. (Da der Name zufällig commons-lang ist, habe ich ihn diesmal mit dem Klassennamen LoggingToStringStyle erstellt.) Rückwirkende Ausgabe mit ReflectionToString - Ein Memorandum

Sie können die Klasse kopieren und einfügen, ändern Sie jedoch nur die folgenden Punkte.

LoggingToStringStyle.java


    protected void appendDetail(StringBuffer buffer, String fieldName, Object value) {
        for(String packaz : recursivePackags) {
            if (value.getClass().getCanonicalName().startsWith(packaz)) {
                // buffer.append(ToStringBuilder.reflectionToString(value, this));
                //↓ Hier ändern
                buffer.append(LoggingToStringBuilder.reflectionToString(value, this));
                return;
            }
        }
        buffer.append(value);
    }

Versuche dich zu bewegen

App.config


    String str = LoggingToStringBuilder.toString(cart, new LoggingToStringStyle("jp.co.pmtech.iwata"));
    System.out.println(str);

Ergebnis


jp.co.pmtech.iwata.Cart[id=1,syohinList=[jp.co.pmtech.iwata.Syohin[id=1,name=Kugelschreiber],jp.co.pmtech.iwata.Syohin[id=2,name=Gewebe]]]

Der Inhalt von Cart und Syohin ist korrekt und der Preis wird nicht angezeigt.

Bonus: andere Möglichkeiten

JSON-Konvertierung

Der Zweck dieser Zeit ist die Ausgabe in das Protokoll, daher ist mir das Ausgabeformat egal. Lassen Sie uns die JSON-Version mit Jackson anzeigen. Wenn Sie die JsonIgnore-Annotation hinzufügen, unterliegt sie keiner JSON-Serialisierung.

Syohin.java


public class Syohin {
    /**Produkt ID*/
    private int id;
    /**Produktname*/
    private String name;
    /**Preis*/
    @JsonIgnore
    private BigDecimal price;
}

App.java


    ObjectMapper mapper = new ObjectMapper();
    String str = mapper.writeValueAsString(cart);
    System.out.println(str);

Ergebnis


{"id":1,"syohinList":[{"id":1,"name":"Kugelschreiber"},{"id":2,"name":"Gewebe"}]}

Ich kann den Preiswert nicht bekommen.

Es gibt nur ein Problem: Es scheint, dass der Rest Controller von Spring Boot von Jackson in JSON konvertiert wurde. Ich habe diese Methode nicht verwendet, weil ich den Preis in die API-Rückgabe aufnehmen wollte. Wenn Sie Jackson nicht verwenden, können Sie diese Methode verwenden.

Rekursive Ausgabe mit RecursiveToStringStyle von commons-lang

Wie oben erwähnt, wurde RecursiveToStringStyle seit 3.2 von commons-lang hinzugefügt. Lass es uns für einen Moment tun. Fügen Sie den folgenden Code am Ende von main ein und führen Sie ihn aus.

App.java


    String str = ReflectionToStringBuilder.toString(cart, new RecursiveToStringStyle());
    System.out.println(str);

Ergebnis


jp.co.pmtech.iwata.Cart@610455d6[id=1,syohinList=java.util.ArrayList@2c7b84de{jp.co.pmtech.iwata.Syohin@5a07e868[id=1,name=Kugelschreiber,price=java.math.BigDecimal@36baf30c[intVal=<null>,scale=0]],jp.co.pmtech.iwata.Syohin@76ed5528[id=2,name=Gewebe,price=java.math.BigDecimal@24d46ca6[intVal=<null>,scale=0]]}] 

Es scheint, dass es rekursiv in eine Zeichenfolge konvertiert wird, aber die Objekt-ID wird angezeigt und ist etwas verrauscht. Darüber hinaus ist der Preis von Big Decimal nicht herausgekommen ...

abschließend

Es ist eine gute Verwendung, aber vielleicht ist es nur ein Holzspucken ... Aus Sicherheitsgründen möchten Sie keine persönlichen Informationen und Kennwörter im Protokoll ausspucken. Ist es auch ein sehr großes Objekt, das Sie protokollieren möchten? ??

Abhängig von den Anforderungen ist JSON oder Commons-lang RecursiveToStringStyle in Ordnung. Der Quellcode wird auf github veröffentlicht. Bitte beziehen Sie sich darauf. https://github.com/pmt-iwata/LoggingToStringBuilder

Recommended Posts

So lassen Sie zu, dass Anmerkungen Elemente festlegen, die Sie nicht ausgeben möchten, wenn Sie ein Objekt rekursiv als Zeichenfolge serialisieren
So schreiben Sie, wenn Sie Zeilenumbrüche und Ausgaben beibehalten und XSS in Rails vermeiden möchten
So geben Sie den Wert aus, wenn sich ein Array im Array befindet
So geben Sie eine Java-Zeichenfolge auf dem Konsolenbildschirm aus
Wenn Sie irgendwo einen Fehler melden möchten, wenn Sie graphql-spring-boot mit Spring Boot verwenden