Container von C++ nach Java



  • Hallo,

    ich wollte hier einmal nachfragen, nachdem ich nach einiger Recherche nichts gefunden habe, wie ich einen Container in Java nutzen kann, ob dies möglich ist und wenn ja, wie.
    Genauer geht es um einen QVector, den ich aber relativ einfach durch einen std::vector ersetzen könnte, der von einer Funktion zurückgegeben wird.
    Durch Qt und JNI kann ich auch relativ einfach Java-Methoden in C++ nutzen, nur andersherum und vor allem in Verbindung mit den Containern bereitet es mir irgendwie Schwierigkeiten.

    Vielen Dank schon einmal im Voraus!



  • Ich bin jetzt kein JNI Experte, aber ich vermute, du musst den komplett kopieren. Also, in Java einen entsprechenden Container erstellen, z.B. ArrayList, und dann einzeln die add Methoden aufrufen.



  • Java kommt mit einer Unmenge an Datenstrukturen 'out of the box'
    --> https://docs.oracle.com/javase/7/docs/technotes/guides/collections/overview.html


  • Mod

    Fricky667 schrieb:

    Java kommt mit einer Unmenge an Datenstrukturen 'out of the box'
    --> https://docs.oracle.com/javase/7/docs/technotes/guides/collections/overview.html




  • SeppJ schrieb:

    Fricky667 schrieb:

    Java kommt mit einer Unmenge an Datenstrukturen 'out of the box'
    --> https://docs.oracle.com/javase/7/docs/technotes/guides/collections/overview.html


    Doch, doch. JNI hat er ja bereits erwähnt und damit geht das in beide Richtungen.


  • Mod

    Fricky667 schrieb:

    SeppJ schrieb:

    Fricky667 schrieb:

    Java kommt mit einer Unmenge an Datenstrukturen 'out of the box'
    --> https://docs.oracle.com/javase/7/docs/technotes/guides/collections/overview.html


    Doch, doch. JNI hat er ja bereits erwähnt und damit geht das in beide Richtungen.

    Genau. Nämlich einmal in die richtige Richtung, und einmal in die dazu entgegengesetzte.



  • In dem Vektor sind Objekte einer eigenen Klasse, die verschiedene QStrings und einen Integer enthält, und er ist meist 1-5 Elemente groß.
    Hat einer von euch ansonsten vielleicht noch eine bessere Idee als alle diese Elemente in einen std::string zu packen und einen jobjectArray zurückzugeben, den ich dann in Java als String[] verwende?
    Das würde ich dann in etwa so machen wie hier beschrieben.
    In Java würde ich diesen Array dann wieder in die Einzelteile zerlegen.
    Oder soll ich lieber in Java ein Äquivalent für die C++-Klasse erstellen?



  • Es funktioniert jetzt folgendermaßen:

    struct MyClass
    {
    	QString s1;
    	QString s2;
    	QString s3;
    	QString s4;
    	int i;
    }
    
    JNIEXPORT jobjectArray JNICALL Java_package_class_function(JNIEnv* env, jobject obj)
    {
    	QVector<QString> vector;
    	for(const auto& a : getResult())	// const QVector<MyClass>& getResult()
    	{
    		vector.push_back(QString());
    		vector.last() += a.s1;
    		vector.last() += '\\';
    		vector.last() += a.s2;
    		vector.last() += '\\';
    		vector.last() += a.s3;
    		vector.last() += '\\';
    		vector.last() += a.s4;
    		vector.last() += '\\';
    		vector.last() += QString::number(a.i);
    	}
    
    	jstring str;
    	jobjectArray result = 0;
    
    	result = env->NewObjectArray(vector.size(), env->FindClass(/*env, */ "java/lang/String"), 0);
    
    	for(int i = 0; i < vector.size(); ++i)
    	{
    		str = env->NewStringUTF(vector[i].toLatin1().data());
    		env->SetObjectArrayElement(result, i, str);
    	}
    
    	return result;
    }
    

    Wenn jemand noch einen besseren Vorschlag hat, bin ich dafür gerne zu haben.

    Da die neuen Probleme nicht hierher passen, werde ich ein neues Thema dafür eröffnen.



  • Das kommt denke ich vor allem auf den konkreten Anwendungsfall drauf an.
    - Wenn dir Performance usw. egal ist, kannst es machen wie in dem Link. Bzw. evtl. auch eine entsprechende Struktur in Java definieren, aber das sind eher Details. Du musst aber bedenken, dass JNI langsam ist und so konvertierst du vielleicht lauter Objekte, die du später gar nicht brauchst
    - Du könntest es auch andersrum machen und in Java einen Proxy um deinen Container und die Objekte dadrin machen, die dann on the fly den entsprechenden C++ Code aufrufen. Wenn du also 1000 Objekte hast und nach 5 break aufrufst, würdest du die nicht alle umsonst konvertieren
    - Ist eh die Frage, ob man so eine Schnittstelle heutzutage noch haben will. Vielleicht wäre es sauberer/wartbarer/schneller, eine Serviceschnittstelle zu definieren und über irgendeinen IPC Mechanismus z.B. Json auszutauschen.



  • Leider muss ich eben irgendwie Java verwenden, um zum Beispiel die Systembenachrichtigungen von Android nutzen zu können. Qt bietet da meines Wissens ja nichts besseres an. Und auch für einen Background-Service, der beim Booten startet, brauche ich Java-Code.
    Deshalb überlegte ich auch anfangs, ob ich nicht alles in Java schreiben will. Aber ich habe mich dann doch für QML entschieden, weil ich Java eigentlich nicht so gerne mag. Nun brauche ich aber eben besagte Schnittstelle zwischen C++ und Java.
    Ich könnte natürlich auch die besagte Funktion in Java neu implementieren und über Java auf die Datenbank zugreifen, aber das wäre auch noch einmal recht umständlich, weil ich dann noch einmal eine weitere Klasse von C++ irgendwie nach Java portieren müsste.

    Folgenden neuen Thread habe ich eröffnet für das neue Problem: https://www.c-plusplus.net/forum/p2536834#2536834

    Performance ist natürlich eigentlich nicht egal, da es das Booten verlangsamt. Aber mir fällt auch keine bessere Lösung ein. 1000 Objekte gibt es auch maximal nur in der C++-Funktion, am Schluss bleiben wie gesagt 1-5 meistens übrig (könnten theoretisch auch mehr sein, ist aber unrealistisch).
    Oder verstehe ich dich falsch?



  • Skylac06 schrieb:

    Oder verstehe ich dich falsch?

    Du hast ein System A mit einem Container, und ein System B, in dem du den Container benutzen willst. Dann hast du grundsätzlich zwei Möglichkeiten:
    1. Du erstellst in System A einen kompletten System B kompatible Container - das ist das was du machst.
    2. Du hast in System B nur einen Wrapper mit den entsprechenden Funktionen wie count, getItem usw., deren Implementierung über JNI in System A rübergreift und die entsprechenden Funktionen aufruft.

    Was besser ist, kommt drauf an. Wenn du eh alle Daten brauchst, ist Variante 1 besser. Wenn du in System B drüberläufst und ziemlich schnell break aufrufst, ist Variante 2 vermutlich besser.

    Was du konkret machst ist eine Mischung aus Variante 1 und meinem dritten Punkt von vorhin. Du serialisierst die Daten sowieso als String. Da wärs vielleicht eine Überlegung wert, alle Daten gleich in einen String zu packen, z.B. als Json. Wie gesagt, Jni ist langsam, evtl. ist es schneller, einen großen String zu erstellen, als x mal SetObjectArrayElement aufzurufen.



  • Ich brauche genau alle Daten in dem Container. Die Daten sind bereits extra so angepasst, dass sie alles enthalten, was gebraucht wird.
    Und du hast natürlich Recht, dass ich dann auch gleich einen längeren String erstellen könnte. Ist vermutlich schneller, auch wenn ich dann noch ein weiteres Trennzeichen brauche. Werde ich dann wohl nocheinmal austauschen, danke.

    JSON ist dann im Prinzip, dass ich die Strings einzeln in eine Datei schreibe und in Java dann wieder auslese, verstehe ich das richtig?
    Ich habe noch nie JSON verwendet, kenne mich deshalb diesbezüglich überhaupt nicht aus.
    Qt scheint ja JSON direkt zu unterstützen, Java aber nicht. Welche Bibliothek würdest du denn dann dafür verwenden?



  • Musst nicht in eine Datei schreibe, Json ist nur ein "Format". Das kannst du genauso als String im Speicher durchreichen.
    Der einzige Vorteil wäre, dass es sich um sowas wie Trennzeichen (sicher, dass di ein deinem String nicht vorkommen können?) kümmert, und das es ein Standard wäre.
    Ich hab schon lang kein Java mehr programmiert, keine Ahnung, was es da aktuell für Bibliotheken gibt, aber da gibts sicher genug. Das ist mittlerweile sowas wie ein Standard für den Datenaustausch mit Webservices, grad auch für Android wichtig.



  • Nein, es ist eben leider nicht sicher. Ich würde dieses Zeichen dann eben nur unnutzbar machen, sodass man es eben nicht mehr verwenden darf.
    Wie reiche ich das denn dann aber im Speicher durch? Über das JNI?

    Okay, danke.
    Sobald ich mein derzeitiges Problem gelöst habe, werde ich mich darum kümmern.


Anmelden zum Antworten