IntelliJ 13.1 und SVN 1.8 (auf Windows)

Heute habe ich einige Zeit damit zugebracht, IntelliJ Idea 13.1 mit unserem Subversion ans Laufen zu bringen. Offensichtlich gibt es einige Bugs, die die Zusammenarbeit mit SVN 1.7 leider erheblich erschweren.

Eine der Möglichkeiten, diese Problematik zu umgehen ist, einfach einen Kommandozeilen-Client für SVN zu nehmen. IntelliJ kann diesen direkt einbinden (Settings -> Version Control -> Subversion -> General -> Use command line client). Unter Windows kann man hierfür zum Beispiel das Binary von SlikSVN nehmen. Damit hat man dann ein SVN-Binary, das man dort nutzen kann. Außerdem ist – bei aktuellem SVN – auch direkt eine Working Copy in Version 1.8 möglich.

Fast.

Denn ab jetzt kommt bei jedem Commit die Fehlermeldung „Could not Commit: wrong revision“ (oder so ähnlich). Komisch … direkt mal untersucht: Commit wurde erfolgreich durchgeführt, Working Copy ist auch korrekt, trotzdem schmeißt IntelliJ diesen Fehler?

Ein wenig auf der Kommandozeile (aka: DOSBox) rumgespielt, den Quelltext der entsprechenden IntelliJ-Klasse angeschaut und dann dämmerte es so langsam …

Beim Nutzen des SVN Kommandozeilen-Clients wird die Rückgabe nach einem Commit geparst, um die neue Revision zu bestimmen. Anscheinend wird dabei angenommen, dass das Programm immer auf Englisch läuft und die Ausgabe daher „Committed revision 123“ lautet. SlikSVN installiert jedoch standardmäßig auch Übersetzungen mit – die Meldung lautet daher „Revision 123 übertragen“. Dies kann IntelliJ nicht korrekt interpretieren, deswegen wird die Fehlermeldung geschmissen. Also einfach die Übersetzungen von SlikSVN deinstallieren, dann klappt auch diese Kombination.

Ich weiß nicht, ob dies nur bei nicht-englischen Windows-Systemen auftritt, aber zumindest ist es etwas, was mich heute geschlagene drei Stunden meiner Zeit gekostet hat!

Korrekte MX Domain Records für web.de

Mir wurde vor kurzem die wenig erfreuliche Nachricht zugetragen, dass man mir anscheinend keine E-Mails an meine @dadadom.de-Adresse schicken könne. Da ich in der Zwischenzeit aber massig E-Mails erhalten hatte, konnte es kein generelles Problem sein.

Schnell stellte sich heraus, dass nur der Versand von web.de aus betroffen war. Ein kurzer Test ergab, dass der Absender nach wenigen Sekunden eine E-Mail mit der Betreffzeile „Mail delivery failed: returning message to sender“ bekommt. Der Inhalt zeigt dann folgende Meldung:

This message was created automatically by mail delivery software.
 
 A message that you sent could not be delivered to one or more of
 its recipients. This is a permanent error. The following address
 failed:
 
 "xyz@dadadom.de":
 domain has no mail exchangers

Das ist natürlich eine Überraschung, insbesondere da alle anderen Provider (1&1, GMX, Google Mail, etc.) keine Probleme mit der Adresse haben. Aber gut, irgendeinen Grund wird es wohl geben und der Grund liegt vermutlich in meiner Zuständigkeit.

Eine kurze Internet-Recherche ergab, dass das Problem im MX-Record meines Domain-Eintrags liegt. Denn in RFC 2181, Absatz 10.3, steht folgendes:

The domain name used as the value of a NS resource record, or part of
   the value of a MX resource record must not be an alias.

Daher ist es natürlich doof, wenn man in seinem DNS-Record so etwas stehen hat wie:

[...]
www  IN A     123.123.123.123
mail IN CNAME www
@    IN MX 10 mail

Die Software bei web.de legt diese Regelung vermutlich strenger aus als die der anderen Provider, das Ändern der dritten Zeile in

mail IN A     123.123.123.123

löst das Problem aber.

Merke: Immer brav an die RFCs halten und nicht mit DNS-Records rumspielen 🙂

Interviewantworten II – die erste Antwort

Die Frage war, warum Object.hashCode() und Object.equals(Object) immer beide überschrieben werden sollten.

Die Antwort findet sich direkt in der Javadoc-Dokumentation von Object.hashCode():

If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result.

Vereinfacht gesagt: Überschreibt man nur equals() und es werden zwei unterschiedliche Instanzen einer Klasse verglichen, die laut equals() aber gleich sind, so bricht man den Kontrakt von Object.hashCode(). Die beiden HashCodes wären unterschiedlich, obwohl die Objekte nach equals() gleich sind.

Um das Ganze ein wenig praktischer zu beschreiben, nehmen wir folgende Klasse an:

public class Person {
  private String firstName;
  private String lastName;
  private Date dateOfBirth;
  private String favoriteBeer;

  // ...getter/setter

  // wir nehmen an, zwei Personen sind identisch, wenn sie gleich heißen und am gleichen Tag geboren wurden

  // bitte IMMER @Override nutzen, wenn Java >= 1.5 verwendet wird!
  @Override
  public boolean equals(Object o) {
    Person otherPerson = (Person) o;
    return
      firstName.equals(o.getFirstName()) &&
      lastName.equals(o.getLastName()) &&
      dateOfBirth.equals(o.getDateOfBirth());
  }
}

In obigem Beispiel wurde nur equals überschrieben und dieser Vergleich macht durchaus Sinn. Aber was passiert, wenn wir zwei Personen gleichen Namens und mit gleichem Geburtsdatum in ein HashSet einfügen wollen? Da das HashSet – wie der Name schon sagt – den HashCode eines Objekts als Vergleichsfunktion heranzieht um zu bestimmen, ob dieses Objekt schon einmal im Set vorhanden ist, würden problemlos beide Objekte im Set abgelegt werden. Und das, obwohl sie doch equals() sind! Hier hilft natürlich, eine .hashCode()-Methode zu schreiben, die genau die gleichen Felder berücksichtigt wie .equals().

Das Erstellen von hashCode und equals ist übrigens mit IDEs einfach gemacht. Unter Eclipse kann man über Source -> generate hashCode() and equals() komfortabel auswählen, welche Felder in die Methoden einbezogen werden sollen. Andere IDEs bieten vermutlich ähnliche Funktionen. Programmatisch kann man über den EqualsBuilder respektive den HashCodeBuilder aus den Apache Commons diese Sachen einfach erledigen.

Interviewfragen II – Java

Hier mal einige Java-spezifische Interviewfragen, die ich teilweise selber erfahren habe, teilweise ich mir aber auch einfach nur ausgedacht habe. Dass sie daher etwas Web-Programmierungs-lastig sind bitte ich zu entschuldigen.

  • Warum sollte
    Object.equals(Object)

    immer überschrieben werden, wenn auch

    Object.hashCode()

    überschrieben wird?

  • Was sind die Unterschiede eines Request-Response-basierten Web-Frameworks im Vergleich zu einem komponentenbasierten Framework? Kennen Sie Beispiele für das eine oder das andere?
  • Was ist der Unterschied zwischen einem Application Server (wie z.B. JBoss AS) und einem Servlet-Container wie z.B. Tomcat?
  • Welche Einsatzszenarien fallen Ihnen für eine Message-Queue ein?
  • Welche Tools kennen Sie, mit denen die Zusammenarbeit zwischen mehreren Entwicklern, Testern und anderen Projektbeteiligten verbessert werden kann?

Diese Fragen werde ich der Reihe nach beantworten, wobei natürlich auch vorab schon Antworten und Vorschläge erwünscht sind!