Frage

Wie kann ich herausfinden, was die Ursache equals () zurückzukehren falsch?

Ich bitte nicht um einen sicheren Wege, immer richtiger Ansatz, aber etwas in dem Entwicklungsprozess zu unterstützen. Zur Zeit muss ich in die Gleichen Schritt () aufruft (in der Regel ein Baum von ihnen), bis einer von ihnen falsch ist, dann wird der Schritt hinein, zum Überdruss.

Ich dachte über das Objektgraph verwendet wird, deren Ausgabe die beiden Objekte zu XML und zu vergleichen. Allerdings Standardkonstruktoren XMLEncoder erfordert, erfordert JiBX Vorkompilierung, x-stream und einfache api sind nicht in meinem Projekt verwendet. Ich habe nichts dagegen nicht eine einzige Klasse zu kopieren, oder sogar ein Paket, in meinen Testbereich und dort verwendet wird, sondern ein ganzes Glas für das Importieren nur nicht passieren werde.

Ich dachte auch über einen Objektgraph traverser mich bauen, und ich kann es immer noch tun, aber ich würde den Umgang mit Sonderfällen beginnen hasse (geordnete Sammlungen, nicht geordnete Sammlungen, Karten ...)

Jede Idee, wie man das macht?

Edit: Ich weiß, dass das Hinzufügen Glas ist die normale Art und Weise, Dinge zu tun. Ich weiß Gläser sind wiederverwendbare Einheiten. die Bürokratie erforderlich (bei meinem Projekt) jedoch dafür rechtfertigt nicht die Ergebnisse. - Ich Debugging halten würde und einen Schritt in

War es hilfreich?

Lösung

Es ist vermutlich kein vollständiger Graph Vergleich ... es sei denn, Ihre equals jede Eigenschaft in jeder Klasse gehört ... (man könnte versuchen ==:))

Versuchen Sie hamcrest Matcher - Sie jeden Matcher in einem "all die" Matcher komponieren :

Matcher<MyClass> matcher = CoreMatchers.allOf(
  HasPropertyWithValue.hasProperty("myField1", getMyField1()),
  HasPropertyWithValue.hasProperty("myField2", getMyField2()));
if (!matcher.matches(obj)){
  System.out.println(matcher.describeFailure(obj));
  return false;
}
return true;

Es wird sagen Dinge wie: ‚erwartet myField1 einen Wert von‚Wert‘zu haben, aber war" ein anderer Wert‘

Natürlich können Sie die statischen Fabriken inline. Das ist ein bisschen schwerer als die Verwendung von Apache-Commons Equals , aber es gibt Ihnen eine genaue Beschreibung, was genau ist fehlgeschlagen.

Sie können Ihre eigenen, spezialisierten Matcher für die schnelle Erstellung dieser Ausdrücke erstellen. Es wäre klug, Apache-Commons Equals kopieren hier.

BTW, der hamcrest Grund jar ist 32K (einschließlich Quelle!) Gibt Ihnen die Möglichkeit, den Code zu überprüfen und sagen zu Ihren Chefs „ich dies als meinen eigenen Code stehen würde“ (was ich vermute, ist die Import-Problem) .

Andere Tipps

Sie könnten Aspekte verwenden „gleich“ auf den Klassen in Ihrem Objektgraphen zu flicken und sie den Objektstatus in eine Datei machen protokollieren, wenn sie false zurück. Um den Objektstatus einloggen könnten Sie so etwas wie Beanutils verwenden, um das Objekt zu untersuchen und kippt ihn. Dies ist ein Glas-basierte Lösung, die leicht in Ihrem Arbeitsbereich verwendet wird

Wenn die Hierarchie der in Ihrem Baum gespeicherten Objekte einfach genug, könnten Sie bedingte Haltepunkte auf der Klassen „gleich“ Implementierung platzieren, die nur ausgelöst, wenn „gleich“ false zurückgibt, welche die Anzahl der Male beschränken würden Sie in Schritt müssen ... Sie können dies nutzen, wo immer Sie Debugger Zugriff haben. Eclipse behandelt diese nur in Ordnung.

Es klingt wie Sie wollen java-diff , oder so ähnlich es.

Okay, das ist eine völlig bizarre Art und Weise, es zu betrachten, aber wie wäre es eine neue statische Methode Einführung:

public static boolean breakableEquals(Object o1, Object o2)
{
    if (o1 == o2)
    {
        return true;
    }
    if (o1 == null || o2 == null)
    {
        return false;
    }
    // Don't condense this code!
    if (o1.equals(o2))
    {
        return true;
    }
    else
    {
        return false;
    }
}

Ich weiß, sieht die letzten bisschen verrückt ... aber der Unterschied ist, dass Sie einen Haltepunkt auf dem „return false“ setzen können. Wenn Sie dann breakableEquals in Ihre tiefe Gleichheit Vergleiche verwenden, dann können Sie brechen, sobald Sie das erste „return false“ getroffen.

Dies hilft nicht viel, wenn Sie viele primitive Werte sind zu vergleichen, allerdings ... aber es könnte hilfreich sein. Ich kann nicht sagen, dass ich das jemals tatsächlich verwendet wird, aber ich kann nicht sehen, warum es nicht funktionieren würde. Es wird ein bisschen weniger effizient sein, natürlich -. Wenn Sie also mit High-Performance-Code zu tun haben, bekommen Sie es wollen danach ändern

Eine andere Möglichkeit wäre so etwas wie zu verwenden:

boolean result = // comparison;
return result;

Angenommen, Ihre IDE unterstützt sie, können Sie dann einen bedingten Haltepunkt auf der return-Anweisung, und stellen Sie den Zustand zu sein „!result“.

Eine weitere Option:

public static boolean noOp(boolean result)
{
    return result;
}

Sie können diese dann verwenden im Vergleich:

return Helpers.noOp(x.id == y.id) &&
       Helpers.noOp(x.age == y.age);

würde ich hoffen, dass, wenn Sie nicht das Debuggen, das durch die JIT wegoptimiert würde - aber auch hier können Sie einen bedingten Haltepunkt in noOp verwenden. Es macht den Code hässlichen, leider.

Kurz gesagt:. Keine besonders Lösungen hier ansprechend, aber nur ein paar Ideen, die Macht Hilfe in bestimmten Situationen

  

Ich habe nichts dagegen nicht eine einzige Klasse zu kopieren,   oder auch ein Paket, in meinen Testbereich   und deren Verwendung dort, aber ein Import   ganzes Glas für diesen gerade geht nicht   passieren.

Um ... was? Hinzufügen ein Glas zu Ihrem Classpath ist, wenn überhaupt, einfacher und weniger störend für das Projekt als das Kopieren Klassen oder ganze Pakete als Quellcode.

Wie für Ihr spezielles Problem, haben Sie eine Menge verschiedener Klassen, die viele verschiedene Eigenschaften verwenden, Gleichheit, um zu bestimmen, oder Sie eine haben Sie gerade tief verschachtelte Objektgraph von im Wesentlichen der gleichen Klassen? Im letzteren Fall wäre es sehr einfach sein, nur die Gleichen strucutre () Methoden, so dass Sie Haltepunkte auf den „return false“ Aussagen setzen. Im ersteren Fall, könnte dies zu viel Arbeit sein, nehme ich an. Aber dann ein XML-basierter Vergleich kann entweder nicht funktionieren, da es Unterschiede zwischen semantisch gleichen Objekten zeigt (z Sets und Maps).

Da Ihr Projekt ein Glas nicht hinzufügen kann, scheint es durchaus über eine SO beantwortet eine ganze Implementierung einer Lösung zu geben, die anderen Projekte eine erhebliche Menge an Code, um zu erreichen (und ist schön in einem Glas für Sie) .

Wie wärs mit einer Nicht-Code-Lösung - bedingten Haltepunkte im Debugger? Sie könnten Haltepunkte, die Reise nur hinzufügen, wenn die Methode false zurückgibt, und legen sie auf allen relevanten Klassen. Kein Schritt.

  

Ich weiß, das Hinzufügen Glas ist die normale Art und Weise, Dinge zu tun. Ich weiß Gläser sind wiederverwendbare Einheiten. die Bürokratie erforderlich (bei meinem Projekt) jedoch dafür rechtfertigt nicht die Ergebnisse. - Ich Debugging halten würde und einen Schritt in

Eine Möglichkeit, dies zu umgehen ist es, eine Bibliothek wie Spring aufzunehmen (die in Lasten anderen Glas zieht) I Frühling Projekt gesehen habe, die eigentlich jeden Frühling Glas nicht nur benutzen, so dass sie jede Dose verwenden könnten, die mit ihm gebündelt.

commons-jxpath könnte nützlich sein, um schnell den Objektbaum zu untersuchen. Ich verstehe Gläser nicht in vollem Umfang das Thema einschließlich, aber man kann es nur in Ihrem eigenen Projekt verwenden, was auch immer in IDE Sie verwenden, die vermutlich können Sie Ausdrücke verwenden, während des Debuggens.

Vielleicht Artikel über Verfahren Verfolgung wird Ihnen helfen.

  

Wie es funktioniert

     

Eine benutzerdefinierte Class Loader liest die Klassendatei und Instrumente jede Methode mit Code Tracing. Der Klassenlader fügt auch ein statisches Feld für jede Klasse. Dieses Feld hat zwei Zustände, ‚auf‘ und ‚off‘. Der Tracing-Code überprüft dieses Feld vor dem Drucken. Die Befehlszeilenoptionen zugreifen und diese ändern diesen statischen Feldausgang zu steuern, zu verfolgen.

Die Beispielausgabe sie zeigen Looks für Ihr Problem viel versprechend, da sie den Rückgabewert einiger Methoden zeigt (wie isApplet):

  

isApplet = false

Es sollte einfach sein, dass Sie die genaue Klasse zu erkennen, die in Gleichen return false gestartet. Hier ist die komplette Beispielausgabe von der Seite:

  

% java -jar /home/mike/java/trace.jar -classpath "/home/mike/jdk1.3/demo/jfc/SwingSet2/SwingSet2.jar" -exclude CodeViewer SwingSet2
  | SwingSet2 ()
.   |. SwingSet2
  | SwingSet2.main ([Ljava.lang.String; @ 1dd95c)
  || isApplet (SwingSet2 @ 3d12a6)
  || isApplet = false
  || SwingSet2.createFrame (apple.awt.CGraphicsConfig@93537d)
  ||SwingSet2.createFrame=javax.swing.JFrame@cb01e3
  || createSplashScreen (SwingSet2 @ 3d12a6)
  ||| createImageIcon (SwingSet2 @ 3d12a6 "splash.jpg", "Splash.accessible_description")
  |||createImageIcon=javax.swing.ImageIcon@393e97
  ||| isApplet (SwingSet2 @ 3d12a6)
  ||| isApplet = false
  ||| GetFrame (SwingSet2 @ 3d12a6)
  |||getFrame=javax.swing.JFrame@cb01e3
  ||| GetFrame (SwingSet2 @ 3d12a6)
  |||getFrame=javax.swing.JFrame@cb01e3
  || createSplashScreen
  .run (SwingSet2 $ 1 @ fba2af)
  ..showSplashScreen (SwingSet2 @ 3d12a6)
  ... isApplet (SwingSet2 @ 3d12a6)
  ... isApplet = false
  ..showSplashScreen
  .run
  || initializeDemo (SwingSet2 @ 3d12a6)
  ||| createMenus (SwingSet2 @ 3d12a6)
  |||| getString (SwingSet2 @ 3d12a6 "MenuBar.accessible_description")
  ||||| getResourceBundle (SwingSet2 @ 3d12a6)
  |||||getResourceBundle=java.util.PropertyResourceBundle@6989e
  |||| getString = "Swing Demo Menüleiste"

XMLEncoder kodiert nur Bean-Eigenschaften, während equals können, offensichtlich, die Arbeit an nicht-Bohnen und und alle internen Felder.

Ein Teil des Problems ist, dass Sie nicht wissen, was gleich ist eigentlich ein Blick auf. Ein Objekt kann viele verschiedenen Felder haben und immer noch behaupten, es zu einem anderen Objekt gleich war, es kann sogar ein diffrent Typ sein. (Zum Beispiel eine benutzerdefinierte URL-Klasse könnte return true für eine Zeichenfolge, die es äußeren Form entspricht).

Also ich glaube nicht, es ist möglich, ohne dass Bytecode Instrumentierung wo Sie die Klassen tatsächlich ändern kann equals () Funktion, um zu sehen, welche Felder auf sie zugreift. Selbst dann wäre es immer noch extreemly schwer zu ‚wirklich‘, warum eine Funktion false zurückgegeben. Aber hoffentlich wäre es eine einfache Frage sein, die Felder zu vergleichen, die in equals tatsächlich zugegriffen werden ()

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top