JSON-Objs aus JSON-Obj filtern und löschen (Manipulation ohne Kenntnis der vollst. Struktur)

vup

Mitglied
Hallo, gleich vorweg, eine (oberflächliche) Suche auf SO brachte mich nicht weiter ...

Ich habe ein gson.JsonObject, in dem mehrere gson.JsonObject e sind. Alle gson.JsonObject e haben ein String-Property namens xyz.

Ich möchte nun alle gson.JsonObject e filtern und löschen, deren xyz-Property-Wert nicht mit aa, bb oder cc enden.

Danach möchte ich das manipulierte gson.JsonObject wieder in ein gson.JsonObject parsen.

Wie kann ich das am einfachsten erreichen? Vielen Dank vorab für jede brauchbare Antwort.
 

mihe7

Top Contributor
Das kommt jetzt natürlich darauf an, was Du mit "am einfachsten" meinst.

Ich verwende mal Gson 2.9.1 (also die Version, die noch nicht asMap() kennt). Man könnte sich nun ein Helferlein schreiben, um den Spaß etwas übersichtlicher zu gestalten:
Java:
static Predicate<Map.Entry<String, JsonElement>> propertyContainsSuffix(
        String property, String suffix) {
    return elem -> ((JsonObject) elem.getValue()).has(property) &&
                   ((JsonObject) elem.getValue()).get(property).getAsString().endsWith(suffix);
}

Damit kann man sich jetzt einen Filter basteln:
Java:
static JsonObject filter(JsonObject obj) {
    Predicate<Map.Entry<String, JsonElement>> toRemove = propertyContainsSuffix("xyz", "aa")
            .or(propertyContainsSuffix("xyz", "bb"))
            .or(propertyContainsSuffix("xyz", "cc"));

    Map<String, JsonElement> map = obj.entrySet().stream()
            .filter(Predicate.not(toRemove))
            .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

    return (JsonObject) new Gson().toJsonTree(map);
}
 

vup

Mitglied
Danke sehr! Es funktioniert aber noch nicht ganz. Ich beschreibe kurz, was ich vorhabe.

Java:
    static Predicate<Map.Entry<String, JsonElement>> propertyContainsSuffix(
            final String property, final String suffix) {
        return elem ->
                ((JsonObject) elem.getValue()).has(property)
                        && ((JsonObject) elem.getValue())
                                .get(property)
                                .getAsString()
                                .endsWith(suffix);
    }

    static JsonObject filter(final JsonObject obj) {
        Predicate<Map.Entry<String, JsonElement>> toRemove =
                propertyContainsSuffix("symbol", "USDT");

        Map<String, JsonElement> map =
                obj.entrySet().stream()
                        .filter(Predicate.not(toRemove))
                        .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

        return (JsonObject) new Gson().toJsonTree(map);
    }

    public static void option5() throws BinanceApiException, Exception {
        BinanceApi accountApi = getAccountApi();
        assert accountApi != null;
        JsonObject jsonObject =
                (new BinanceRequest("https://www.binance.com/api/" + "v1/exchangeInfo"))
                        .read()
                        .asJsonObject();
        System.out.println("jsonObject = " + jsonObject);
        jsonObject = filter(jsonObject);
        System.out.println("jsonObject = " + jsonObject);
        BinanceExchangeInfo info = new BinanceExchangeInfo(jsonObject);
        System.out.println("info = " + info);

Fehlermeldung:

Code:
Exception in thread "main" java.lang.ClassCastException: class com.google.gson.JsonPrimitive cannot be cast to class com.google.gson.JsonObject (com.google.gson.JsonPrimitive and com.google.gson.JsonObject are in unnamed module of loader 'app')
        at Main.lambda$propertyContainsSuffix$3(Main.java:361)
        at ...
        at Main.filter(Main.java:377)
        at Main.option5(Main.java:390)
        at Main.startMenu(Main.java:541)
        at Main.main(Main.java:550)

Ich nutze diese Api: https://github.com/webcerebrium/java-binance-api

Ich will nicht meckern, aber diese Api ist 4 Jahre alt und enthält einen Fehler, weil inzwischen neue symbols zu binance hinzugefügt wurden.

Es gibt die Methode exchangeInfo() :

Java:
    public BinanceExchangeInfo exchangeInfo() throws BinanceApiException {
        JsonObject jsonObject = (new BinanceRequest(this.baseUrl + "v1/exchangeInfo")).read().asJsonObject();
        return new BinanceExchangeInfo(jsonObject);
    }

Diese parst das json result in ein BinanceExchangeInfo-Objekt. Intern wird dabei aber folgendes überprüft:

Java:
    public BinanceSymbol(String symbol) throws BinanceApiException {
        if (Strings.isNullOrEmpty(symbol)) {
            throw new BinanceApiException("Symbol cannot be empty. Example: BQXBTC");
        } else if (symbol.contains(" ")) {
            throw new BinanceApiException("Symbol cannot contain spaces. Example: BQXBTC");
        } else if (!symbol.endsWith("BTC") && !symbol.endsWith("ETH") && !symbol.endsWith("BNB") && !symbol.endsWith("USDT")) {
            throw new BinanceApiException("Market Symbol should be ending with BTC, ETH, BNB or USDT. Example: BQXBTC. Provided: " + symbol);
        } else {
            this.symbol = symbol.replace("_", "").replace("-", "").toUpperCase();
        }
    }

Sprich: Jedes symbol muss mit BTC, ETH, BNB oder USDT enden.

Meine Überlegung war erst, mithilfe von Reflection den Konstruktor dynamisch zu ändern (quasi zu "mocken") - aber das funktioniert nicht.

Deshalb möchte ich die Anfrage einfach selber stellen, und das JsonObject einfach filtern/ändern.

@mihe7 : Hast du eine Idee, wie es auch mit com.google.gson.JsonPrimitive s funktionieren könnte?
 

vup

Mitglied
Vielleicht, damit das Problem einfacher nachgestellt bzw. reproduziert werden kann:

Java:
import com.google.gson.JsonObject;
import com.webcerebrium.binance.api.BinanceApi;
import com.webcerebrium.binance.api.BinanceApiException;
import com.webcerebrium.binance.api.BinanceRequest;
import com.webcerebrium.binance.datatype.BinanceExchangeInfo;

public class Main2 {
    public static void main(final String[] args) throws BinanceApiException {
        BinanceApi api = new BinanceApi();
        JsonObject jsonObject = (new BinanceRequest("https://www.binance.com/api/" + "v1/exchangeInfo")).read().asJsonObject(); // is working
        System.out.println("jsonObject = " + jsonObject); // is working

        BinanceExchangeInfo info = api.exchangeInfo(); // is NOT working, Exception, program ends with exit code 1
        System.out.println("info = " + info);
    }
}

pom.xml:

XML:
    <dependencies>
        <dependency>
            <groupId>com.webcerebrium</groupId>
            <artifactId>binance-api</artifactId>
            <version>1.0.9</version>
        </dependency>
        
    </dependencies>
 

KonradN

Super-Moderator
Mitarbeiter
is NOT working, Exception, program ends with exit code 1
Generell wäre es schon gut, wenn man statt nur so einem Hinweis evtl. auch mal die Exception bringen würde.

Code:
Exception in thread "main" com.webcerebrium.binance.api.BinanceApiException: Market Symbol should be ending with BTC, ETH, BNB or USDT. Example: BQXBTC. Provided: BTCTUSD
    at com.webcerebrium.binance.datatype.BinanceSymbol.<init>(BinanceSymbol.java:19)

Die gewählte Library ist offensichtlich zu alt und unterstützt die USD Einträge nicht wie BTCTUSD.

Wenn Du diese Library nutzen willst, dann reicht evtl. ein einfaches Anpassen der Library - da wäre dann in BianceSymbol.java in Zeile 18 der Check zu erweitern:
if (!symbol.endsWith("BTC") && !symbol.endsWith("ETH")&& !symbol.endsWith("BNB") && !symbol.endsWith("USDT") && !symbol.endsWith("USD")) {
(Sprich: entweder einfach https://github.com/webcerebrium/java-binance-api holen und anpassen oder ein Fork auf GitHub erzeugen. Da muss dann auch die gradle Config angepasst werden und und und ... )

Aber ob dieser eine Punkt schon ausreicht oder ob es da dann ggf. noch Folgeprobleme geben wird, kann ich nicht sagen.

Daher ist es evtl. einfacher, zu schauen, ob bei den 1.119 biance Projekten auf GitHub, die java nutzen, evtl. nicht etwas aktuelleres, besseres zu finden ist.
 

vup

Mitglied
Nein nein, ich selber passe diese Library nicht an. Ich will nur den Fehler beheben. Und die Fehlermeldung habe ich gepostet, wie du vielleicht im vorherigen Beitrag sehen kannst.
 

KonradN

Super-Moderator
Mitarbeiter
Also du willst nicht:
  • eine andere Library nutzen
  • den Code der Library selbst anpassen und neu übersetzen

Du willst einfach die vorhandene Library nutzen und dann "patchen", damit der Konstruktor funktionert.

Den Sinn dahinter verstehe ich aber nicht, aber wenn das wirklich das ist, was Du möchtest, dann nehmen wir einfach einmal aus dem Konstruktor alle Checks raus:

Java:
    public static void main(final String[] args) throws BinanceApiException, NotFoundException, CannotCompileException {
        ClassPool pool = ClassPool.getDefault();
        CtClass ctClass = pool.get("com.webcerebrium.binance.datatype.BinanceSymbol");
        CtClass[] parameterTypes = new CtClass[] { pool.get("java.lang.String") };
        CtConstructor ctConstructor = ctClass.getDeclaredConstructor(parameterTypes);

        // Set the new constructor body
        ctConstructor.setBody("{ this.symbol = $1.replace(\"_\", \"\").replace(\"-\", \"\").toUpperCase(); }");

        // Use the modified class
        Class<?> modifiedClass = ctClass.toClass();

        BinanceApi api = new BinanceApi();
        BinanceExchangeInfo info = api.exchangeInfo();
        System.out.println("info = " + info);
    }

Das würde jetzt Javassist nutzen um den Konstruktor zu ersetzen, sprich an Abhängigkeiten hätten wir:

XML:
        <dependency>
            <groupId>com.webcerebrium</groupId>
            <artifactId>binance-api</artifactId>
            <version>1.0.9</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.javassist/javassist -->
        <dependency>
            <groupId>org.javassist</groupId>
            <artifactId>javassist</artifactId>
            <version>3.29.2-GA</version>
        </dependency>

Mit Java 9+ muss man noch java.base/java.lang öffnen, also man braucht beim Start den Parameter:
--add-opens java.base/java.lang=ALL-UNNAMED

Das ist aber explizit keine Lösung, die ich empfehlen würde!
 

vup

Mitglied
Vielen Dank. Dann funktioniert es ja doch mit Reflection bzw. einer zusätzlichen Library.

Ich werde aber dennoch weiter versuchen, das json zu ändern, vielleicht geht es damit auch.
 

vup

Mitglied
Es hat geklappt 😁 Zwar nicht so schön mit Streams und Lambdas, aber es geht:

Java:
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.webcerebrium.binance.api.BinanceApiException;
import com.webcerebrium.binance.api.BinanceRequest;
import com.webcerebrium.binance.datatype.BinanceExchangeInfo;

import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

public class Main2 {
    public static JsonObject filter(final JsonObject obj) {
        Set<Map.Entry<String, JsonElement>> entries = obj.entrySet();
        Set<Map.Entry<String, JsonElement>> entries2 = new HashSet<>();
        for (final Map.Entry<String, JsonElement> me : entries) {
            if (me.getKey().equals("symbols")) {
                JsonArray ja = new JsonArray();
                for (final JsonElement je : me.getValue().getAsJsonArray()) {
                    if (je.isJsonObject() && je.getAsJsonObject().has("symbol")) {
                        if (je.getAsJsonObject().get("symbol").getAsString().endsWith("USDT")) {
                            ja.add(je);
                        }
                    } else {
                        ja.add(je);
                    }
                }
                entries2.add(Map.entry(me.getKey(), ja));
            } else {
                entries2.add(me);
            }
        }
        Map<String, JsonElement> map = entries2.stream().collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
        return (JsonObject) new Gson().toJsonTree(map);
    }

    public static void main(final String[] args) throws BinanceApiException {
        JsonObject jsonObject = (new BinanceRequest("https://www.binance.com/api/" + "v1/exchangeInfo")).read().asJsonObject();
        jsonObject = filter(jsonObject);
        BinanceExchangeInfo info = new BinanceExchangeInfo(jsonObject);
        System.out.println("info = " + info);
    }
}

Das ist aber explizit keine Lösung, die ich empfehlen würde!

Bevor man etwas generell ablehnt, sollte man vielleicht das Wieso erklären. Aber jeder darf gern seine Meinung haben.
 

vup

Mitglied
Wenn der Motor deines Autos kaputt ist, schmeißt du es dann weg und kaufst dir ein Neues? (Jetzt mal unabhängig davon, dass das mittlerweile nicht mehr so einfach geht)
 

KonradN

Super-Moderator
Mitarbeiter
Bevor man etwas generell ablehnt, sollte man vielleicht das Wieso erklären. Aber jeder darf gern seine Meinung haben.
Sorry, ich habe es nicht generell abgelehnt, ich habe es nur nicht empfohlen. Das sind zwei unterschiedliche Dinge! Und das war ganz klar meine Meinung. Und natürlich kannst Du die Meinungen auch gewichten - Du hast jetzt zwei Meinungen:
  • eine von jemandem, der mal eben so diesen Code aus den Ärmeln geschüttelt hat und somit von jemandem, der sich damit auskennt
  • eine von jemandem, der diese Möglichkeiten bisher so noch nicht kannte und ich sage es mal ganz salop: Wie der Ochs vorm Berg stand.
Aber klar - eine Meinung war von dir - die wirst Du natürlich bevorzugen, da Du nicht über den Punkt nachdenkst sondern nur aus dem Bauch heraus entscheidest. (Was ok ist für mich! Ich habe damit kein Problem!)

Aber wenn Du so freundlich nach einer Erläuterung fragst:

Was wir hier machen ist ja keine saubere Software Entwicklung sondern wir frickeln da irgendwie an etwas herum. Die Änderung kann man ja machen, aber dann doch bitte an dem eigentlichen Werk. Und das sind die Sourcen, die ja zur Verfügung stehen.

Wenn man das macht, dann kann man z.B. einen Pull Request zurück geben. Das ist bei Open Source so halt üblich: Es ist ein Nehmen und Geben.

Wenn Du da unbedingt ein Auto-Vergleich haben willst: Wenn die Lenkung nicht mehr geht:
  • reparierst Du dann das Auto?
  • Bastelst Du irgendwas Externes zusammen, womit Du dann lenkst? (Also eine Vorrichtung, die Lenkbar ist und das kommt dann vorne unter Dein Auto und Das Auto ist defekt, aber Du hast da ja jetzt etwas, womit Du lenken kannst...)

Du musst Dir ja nur rein praktische Fragen stellen:
  • wie gut kannst Du diese Lösung weiter ausbauen? Was für Tools unterstützen Dich da z.B.?
  • wie gut kannst Du die Qualität sicher stellen?

Diese beiden Fragen kannst Du ja auch einfach praktisch beantworten:
a) baue doch die Checks, die ich rausgenommen habe, wieder ein.
b) teste den Code über einen Unit Test.
 

vup

Mitglied
Danke für die Erläuterung!

Die Änderung kann man ja machen, aber dann doch bitte an dem eigentlichen Werk. Und das sind die Sourcen, die ja zur Verfügung stehen.
Ich finde dabei aber problematisch, dass praktisch alles auf GitHub auch eine Lizenz hat. Das heißt, wenn es suboptimal läuft, dürfte man die Library an sich gar nicht ändern...

Aber unabhängig davon: Ich denke(™), man müsste nur folgende Bedingung erweitern bzw. weniger restriktiv machen:

Java:
} else if (!symbol.endsWith("BTC") && !symbol.endsWith("ETH") && !symbol.endsWith("BNB") && !symbol.endsWith("USDT")) {

Und dann müsste man... wie völlig richtig gesagt... sicherstellen durch Tests, dass alles noch funktioniert. Ich habe mich mit dem Test-Coverage dieser Library aber nicht näher befasst.

Wenn es dich in den Fingern juckt, dann eröffne doch selber so ein Issue bzw. PR ... Binance listet ihre "Markets" hier https://www.binance.com/en/trade-rule auf.
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
I JSON in Objekt umwandeln Java Basics - Anfänger-Themen 3
J JSON mit einem JPanel Java Basics - Anfänger-Themen 3
J Objekte in JSON speichern?? Java Basics - Anfänger-Themen 1
I JSON / XML Struktur mit Vererbung / Interfaces Java Basics - Anfänger-Themen 0
I API - zurückgegebener JSON String lesen und in Entity konvertieren Java Basics - Anfänger-Themen 2
I JSON - cannot deserialize from Object value Java Basics - Anfänger-Themen 16
S JSON einlesen und benutzen Java Basics - Anfänger-Themen 5
HolyFUT JSON String in Java Object schreiben - Anführungszeichen rauskriegen? Java Basics - Anfänger-Themen 17
BATMAN_2008 Jackson adding additional fields to JSON throws java.util.concurrent.CompletionException: Java Basics - Anfänger-Themen 2
I JSON und Interface Java Basics - Anfänger-Themen 3
J Wert in einer json Datei ändern und speichern Java Basics - Anfänger-Themen 3
J Json Datei auslesen Java Basics - Anfänger-Themen 4
J JSON-HashMap Java Basics - Anfänger-Themen 3
P JSON-Array auf Excel-Spalten verteilen? Java Basics - Anfänger-Themen 5
P Variablen HttpResponse.getBody() wird automatisch org.json Object und kann nicht zu json.simple Object gecastet werden? Java Basics - Anfänger-Themen 7
P Ressourcen für JSON & API Informationen? Java Basics - Anfänger-Themen 1
D JSON in JSOUP ELEMENTS Java Basics - Anfänger-Themen 1
M Wie analysiert JSON eine toString-Ausgabe ? Java Basics - Anfänger-Themen 1
F POST-Request mit json - Abfrage mit Java Java Basics - Anfänger-Themen 2
R Value von einem JSON-Objekt ausgeben Java Basics - Anfänger-Themen 4
S JSON Datei schreiben und lesen Java Basics - Anfänger-Themen 3
F Kann JSON nicht deserialisieren Java Basics - Anfänger-Themen 0
R JSON Array Java Basics - Anfänger-Themen 4
E Erste Schritte Wie führe ich org.json.jar aus? Java Basics - Anfänger-Themen 6
M JSON Format Java Basics - Anfänger-Themen 5
I JSON Datei in Array umwandeln Java Basics - Anfänger-Themen 1
A JSON Lesen und Schreiben. Java Basics - Anfänger-Themen 3
L Jackson JSON parsen Java Basics - Anfänger-Themen 7
A JSON versenden Java Basics - Anfänger-Themen 2
N JSON - komme nicht weiter Java Basics - Anfänger-Themen 2
Y Fehler in Json Datei Java Basics - Anfänger-Themen 4
F JSON null macht mir ein Problem Java Basics - Anfänger-Themen 3
N Suchfeld, JSON Java Basics - Anfänger-Themen 2
F JSON in dokumentierten Format als PDF Java Basics - Anfänger-Themen 3
P JSON-Konfigurationsdatei verwenden: Probleme mit Pfad Java Basics - Anfänger-Themen 1
J JSON Java Basics - Anfänger-Themen 2
F JSON von XBMC Java Basics - Anfänger-Themen 1
Traxter JSON in Java Java Basics - Anfänger-Themen 15
J String aus Json File parsen Java Basics - Anfänger-Themen 6
B Best Practice JSON Datei zerlegen Java Basics - Anfänger-Themen 1
Joew0815 Interface JSON Objekte aus Java Objekten erzeugen Java Basics - Anfänger-Themen 9
C XML und/oder JSON Java Basics - Anfänger-Themen 3
J Funktion um JSON per Post senden/emfangen Java Basics - Anfänger-Themen 3
L Input/Output JSON Objekt abrufen und ausgeben Java Basics - Anfänger-Themen 9
D JSON Java Basics - Anfänger-Themen 4
R JSON - Ausgabe als HTML mit gson Java Basics - Anfänger-Themen 6
F JSON to JAVA (und vice versa) Java Basics - Anfänger-Themen 2
M JSON Datensätze aus Website in Tabelle Java Basics - Anfänger-Themen 17
C Java, Javascript, Dojox und JSON Java Basics - Anfänger-Themen 4
S JSON String in Object umwandeln Java Basics - Anfänger-Themen 3

Ähnliche Java Themen

Neue Themen


Oben