Jdbi: Eingebauter Mapper für ZonedDateTime verwirft Zeitzoneninformationen

Erstellt am 21. Dez. 2017  ·  43Kommentare  ·  Quelle: jdbi/jdbi

Es gibt einen eingebauten Mapper für ZonedDateTime der so aussieht, als würde TIMESTAMP WITH TIME ZONE SQL direkt unterstützt, aber der Mapper tut dies nicht.

Ich denke, es ist nicht das Richtige, einen Mapper für einen zonenbewussten Typ bereitzustellen, der zonenunbewusst ist.

bug feature improvement

Hilfreichster Kommentar

Um ehrlich zu sein, stimme ich @findepi zu, wo er sagte, dass jdbi keine Mapper für Dinge bereitstellen sollte, die eigentlich nicht genau abgebildet werden können, wie Zeitzonen / Offsets, die nicht beibehalten werden ... Die Idee eines "Kompromisses" hier klingt sehr gefährlich für mich - Ich habe die vollständige Datenintegrität immer als eine der höchsten Prioritäten in jedem Projekt angesehen. Benutzer sollten nicht überprüfen müssen, ob Bibliotheken richtig funktionieren.

Ich würde eher mit einer Laufzeitausnahme während eines Testlaufs herausfinden, dass jdbi keinen Mapper für einen bestimmten Typ bereitstellt und dann selbst einen schreiben, als herauszufinden, wer weiß wann, dass ein von jdbi bereitgestellter Mapper heimlich verändert wurde meine Daten.

Ich habe einen großen Komponententest, der Werte vieler Typen schreibt und dann liest, um die Korrektheit der Implementierung/Datenintegrität sowohl in der Datenbank selbst (hsqldb) als auch in jdbi zu überprüfen, damit ich jdbi-Mapper/Argumente schreiben kann, um alle Probleme zu behandeln. Ich musste jetzt mehrere schreiben, weil hsqldb derzeit im Grunde keine Unterstützung für java.time bietet, obwohl die Spezifikation dies sagt (riesiger Fehler). Ich hatte noch nicht daran gedacht, java.time-Objekte mit anderen Zonen/Offsets als meinem System zu testen, also habe ich es einfach getan, und tatsächlich kommen sie alle mit dem Offset/Zonen-Reset auf Systemwerte zurück, aber aufgrund der Zuordnung von jdbi zu Timestamp, nicht wegen hsqldb-Bugs.

Ich schlage vor, diese fehlerhaften Mapper aus jdbi3 zu entfernen und in herstellerspezifische Artefakte (jdbi3-hsqldb und andere) zu verschieben, wo ihre Implementierung vollständig korrigiert werden kann.

Ich kann jdbi-hsqldb vielleicht selbst beisteuern, da ich sowieso alle notwendigen Mapper und Argumente für mein eigenes Projekt geschrieben habe.

Alle 43 Kommentare

Sie haben Recht, aber das ist alles, was JDBC derzeit unterstützt. Wir müssen alle java.time-Typen in java.util- oder java.sql-Typen konvertieren, denen Zeitzonen-/Offset-Daten fehlen.

Verwenden Sie aus Neugier Postgres? Weil sich ihr TIMESTAMP WITH TIME ZONE anders verhält, als Sie es erwarten würden.

verwendest du Postgres? Weil sich ihr TIMESTAMP WITH TIME ZONE anders verhält, als Sie es erwarten würden.

Ich bin mir bewusst. (Große Enttäuschung für ansonsten sehr standardkonforme Datenbank übrigens.)

Sie haben Recht, aber das ist alles, was JDBC derzeit unterstützt.

Ich hatte erwartet, dass JDBI org.h2.api.TimestampWithTimeZone H2 ziehen würde, ohne dass ich dies manuell tun müsste, _irgendwie_.
Da ich keine "tragbare" (mit verschiedenen Treibern arbeitende) Möglichkeit kenne, den TIMESTAMP W / TZ-Wert abzurufen, habe ich keine echte Lösung.
Wenn Sie jedoch nicht alle Informationen abrufen, sollten Sie nicht so tun, als ob Sie dies tun würden - dh IMO sollte es keinen eingebauten Mapper für ZonedDateTime . Ansonsten machst du es wie Postgres - nicht das, was ich erwarten würde.

Ich denke, es ist immer noch praktisch, wenn ein Benutzer ZonedDateTime möchte und es nicht interessiert, dass es in der Zeitzone des App-Servers statt in der Zeitzone der Datenbank zurückgegeben wird.

Dropwizard verwendet übrigens eine andere Version des Mappers für JDBI2, bei der ein Benutzer die Zeitzone der Datenbank explizit festlegen kann: https://github.com/dropwizard/dropwizard/blob/master/dropwizard-jdbi/src/main/java /io/dropwizard/jdbi/args/ZonedDateTimeMapper.java

Wenn Sie Beispielcode zum Abrufen/Festlegen von ZonedDateTime mit H2 bereitstellen könnten, würde ich das gerne dem Plugin hinzufügen.

Ich denke, es ist immer noch praktisch, wenn ein Benutzer ZonedDateTime verwenden möchte und es nicht interessiert, dass es in der Zeitzone des App-Servers statt in der Zeitzone der Datenbank zurückgegeben wird.

@arteam , Wenn der Benutzer sich dieser Wahl bewusst ist - stimme ich zu.

Allerdings funktioniert AFAIR https://github.com/jdbi/jdbi/blob/master/core/src/main/java/org/jdbi/v3/core/mapper/BuiltInMapperFactory.java#L182 nicht einmal auf H2 für TS w TZ, da rs.getTimestamp(..) für diesen Typ nicht unterstützt wird.

Wenn Sie Beispielcode zum Abrufen/Einstellen von ZonedDateTime mit H2 bereitstellen könnten, würde ich diesen gerne dem Plugin hinzufügen.

Ich kenne keinen portablen Weg - der einzige Weg, den ich kenne, ist (org.h2.api.TimestampWithTimeZone) rs.getObject(..) und für zB Oracle wäre es ähnlich, aber mit Oracle-spezifischer Klasse.

Im Allgemeinen würde ich es vorziehen, von der API _erzwungen_ zu werden, um die richtige Transformation zu verwenden (Zeitstempel in LocalDateTime ) und "zone-ing" explizit hinzuzufügen.

Sie scheinen anderer Meinung zu sein, was bedeutet, dass es keinen Sinn macht, dieses Thema offen zu halten.

Eine Sache, die wir in unserem Stack machen, ist, dass wir tatsächlich behaupten, dass Javas Zeitzone == Postgres' Zeitzone ist. In diesem Fall funktioniert alles genau richtig. Sollten wir vielleicht eine Warnung ausgeben, wenn eine Abweichung vorliegt? Wäre das ein OK-Kompromiss zwischen der Aktivierung von Funktionen, die die Leute erwarten, und der TZ-Korrektur?

Ich bin mir nicht sicher, warum Sie das so schnell geschlossen haben, ich hatte das Gefühl, es gäbe noch mehr zu besprechen.

Auch wenn wir dies nicht generisch für alle Anbieter auflösen können, können wir dies auf jeden Fall pro Anbieter unterstützen.

Die Mapper und Argumentfactorys, die mit Jdbi ausgeliefert werden, können einfach überschrieben werden, indem ein anderer Mapper/Argument registriert wird. Die zuletzt registrierte (pro Typ) gewinnt.

Wenn Sie sich die Quelle für PostgresPlugin ansehen, werden Sie feststellen, dass sie JavaTimeMapperFactory registriert, was alternative Mapper mit ResultSet.getObject(Class) für LocalDate , LocalTime bereitstellt LocalDateTime und OffsetDateTime , die direkt vom Postgres JDBC-Treiber unterstützt werden.

Wenn H2 eine Möglichkeit hat, ZonedDateTime zu speichern, ohne die Zone zu entfernen, können wir H2DatabasePlugin ändern, um dafür einen benutzerdefinierten Mapper zu verwenden.

Ich werde das vorerst wieder öffnen, hier gibt es gute Diskussionen und wichtig , die Dinge richtig zu machen! Wir sind auch einfach pragmatisch und die Leute erwarten, die Zeittypen tatsächlich nutzen zu können...

Verstehe ich aus dieser Konversation richtig, dass das jdbi-Team daran interessiert wäre, z. B. ein jdbi3-hsqldb-Unterprojekt/Artefakt/... Wandlung)?

Absolut.

Um ehrlich zu sein, stimme ich @findepi zu, wo er sagte, dass jdbi keine Mapper für Dinge bereitstellen sollte, die eigentlich nicht genau abgebildet werden können, wie Zeitzonen / Offsets, die nicht beibehalten werden ... Die Idee eines "Kompromisses" hier klingt sehr gefährlich für mich - Ich habe die vollständige Datenintegrität immer als eine der höchsten Prioritäten in jedem Projekt angesehen. Benutzer sollten nicht überprüfen müssen, ob Bibliotheken richtig funktionieren.

Ich würde eher mit einer Laufzeitausnahme während eines Testlaufs herausfinden, dass jdbi keinen Mapper für einen bestimmten Typ bereitstellt und dann selbst einen schreiben, als herauszufinden, wer weiß wann, dass ein von jdbi bereitgestellter Mapper heimlich verändert wurde meine Daten.

Ich habe einen großen Komponententest, der Werte vieler Typen schreibt und dann liest, um die Korrektheit der Implementierung/Datenintegrität sowohl in der Datenbank selbst (hsqldb) als auch in jdbi zu überprüfen, damit ich jdbi-Mapper/Argumente schreiben kann, um alle Probleme zu behandeln. Ich musste jetzt mehrere schreiben, weil hsqldb derzeit im Grunde keine Unterstützung für java.time bietet, obwohl die Spezifikation dies sagt (riesiger Fehler). Ich hatte noch nicht daran gedacht, java.time-Objekte mit anderen Zonen/Offsets als meinem System zu testen, also habe ich es einfach getan, und tatsächlich kommen sie alle mit dem Offset/Zonen-Reset auf Systemwerte zurück, aber aufgrund der Zuordnung von jdbi zu Timestamp, nicht wegen hsqldb-Bugs.

Ich schlage vor, diese fehlerhaften Mapper aus jdbi3 zu entfernen und in herstellerspezifische Artefakte (jdbi3-hsqldb und andere) zu verschieben, wo ihre Implementierung vollständig korrigiert werden kann.

Ich kann jdbi-hsqldb vielleicht selbst beisteuern, da ich sowieso alle notwendigen Mapper und Argumente für mein eigenes Projekt geschrieben habe.

Ich stimme zu, dass dies wahrscheinlich der klügere Weg gewesen wäre, aber zu diesem Zeitpunkt wird v3 veröffentlicht und die Katze ist aus dem Sack.

Das Entfernen dieser Mapper oder Argumentfactorys wäre eine bahnbrechende Änderung für alle bestehenden Benutzer, die von ihnen abhängig sind.

Wenn jemand bereits auf sie angewiesen ist (sind sich ihrer Fehler bewusst oder nicht), wäre es für diese Benutzer einfach genug, sie wieder einzufügen: Die Konvertierungen sind so ziemlich Einzeiler. Auf der anderen Seite führt dies dazu, dass immer mehr Leute wie ich davon ausgehen, dass es funktioniert, weil es bereitgestellt wird (ehrlich, wer kennt alle technischen Spezifikationen wie die Nicht-Unterstützung von Zeitzonen durch jdbc auswendig?) und können oder können nicht finden später heraus, dass ihre Daten falsch gehandhabt wurden...
Grundsätzlich denke ich, dass der potenzielle zukünftige Schaden durch das Bleiben von ihnen viel größer ist als der Schaden, der jetzt den wenigen zugefügt wird, die durch das Entfernen aktualisiert haben.

@TheRealMarnes Ich denke, das Entfernen einer Funktion (auch wenn wir uns einig sind, dass sie nicht existieren sollte) ist nicht so einfach. Die Leute neigen dazu, eine semantische Versionierung anzunehmen (unabhängig davon, ob das Projekt ihr folgt oder nicht). Ich kenne die Projektregeln nicht, aber normalerweise würdest du es höchstens in v3 verwerfen (hier ist die Veraltung schwierig, da es keine API-Methode gibt, die als veraltet markiert werden kann, Dokumentation und Protokollierung ist das, was übrig bleibt) und die Funktion in v4 entfernen , in der erwartet wird, dass die Benutzer die Versionshinweise / den Migrationsleitfaden lesen.

Ich stimme zu, dass so etwas nie einfach ist und die Lösungen immer jemanden unglücklich machen werden, aber ich neige dazu, zu denken, dass der Zweck die Mittel heiligt und ein fehlerhaftes System durch ein besseres zu ersetzen ist auf lange Sicht immer den Umsturz wert. Und ich denke nicht, dass es unvernünftig ist, von den Leuten zu erwarten, dass sie die Versionshinweise / Migrationsleitfäden lesen... Mit Wartung und kleineren Updates, sicher, aber nicht mit einem großen Update. Jdbi3 selbst ist unbrauchbar, wenn man von jdbi2 kommt, ohne auch das neue Handbuch zu lesen.

Ich denke, ich könnte eine Lösung finden, um diese Mapper / Argumente zu deaktivieren, vorausgesetzt, die Wiederherstellung war ein Einzeiler - vielleicht verschieben Sie diese Mapper in ein Plugin?

Wie ein nicht herstellerspezifisches jdbi3-core-experimental ?
Edit: mein Fehler, du meinst jdbi.installPlugin(new ExperimentalMappersPlugin())

Das wäre die Idee, obwohl diese nicht wirklich "experimentell" sind.

TimezoneInsensitiveJavaTimeMappers dann :P

Es sind nicht nur die Mapper, sondern auch die Argumentfabriken.

Wie wäre es mit JavaTimeYoloTZPlugin :wink:

Auch wenn wir dies nicht generisch für alle Anbieter auflösen können, können wir dies auf jeden Fall pro Anbieter unterstützen.

@qualidafial Ich habe kürzlich erfahren, dass es einen aufkommenden De-facto-Standard zum Abrufen von Datums- / Uhrzeitwerten in der Welt nach Java8 zu geben scheint.

Zuerst ein bisschen mehr Hintergrund:

  • Ich habe dieses Problem zur JDBI-Konvertierung von TIMESTAMP WITH TIME ZONE in ZonedDateTime , die Zeitzoneninformationen verwirft
  • Es gibt ein weiteres Problem mit allen JDBC-APIs. So sollen TIMESTAMP , DATE , TIME Objekte abgerufen werden, dh mit java.sql.{Timestamp,Date,Time} Klassen. Die Klassen erstrecken sich alle von java.util.Date . Erinnert sich noch jemand daran, wie Calendar eingeführt wurde und die Methoden von java.util.Date , die sich mit Jahr/Monat/Tag/Stunde/Minute/Sekunde befassen, veraltet waren? Aus gutem Grund (und ich meine nicht, dass Calendar alle Probleme gelöst hat).

    • Sie können java.sql.Timestamp aus einer Datenbank abrufen, wenn Ihre _JVM-Zeitzone_ eine solche Ortszeit nicht beachtet. So kann eine in den USA laufende App einen Zeitstempelwert von 2017-03-26 02:30:00 (ohne Zone!) in einer gemeinsamen Datenbank speichern, eine in Europa laufende App (mit zB Europe/Berlin als JVM-Zone) jedoch nicht in der Lage sein, diesen Zeitstempel abzurufen, da es zu dieser Zeit in Europa DST gab.

    • oh, dasselbe gilt für java.sql.Date , da dies fast identische Klasse ist. java.sql.Date stellt das Datum dar, als ob es um Mitternacht java.sql.Timestamp , aber manchmal gibt es keine Mitternacht. Es gibt Zonen mit DST-Änderungen um Mitternacht (entweder aktuell oder in der Vergangenheit).

    • würden Sie denken, dass java.sql.Time dieses Problem nicht hat, weil es die abgerufene Zeit als Zeitstempel am 01.01.1970 darstellt? Leider nein, da es Zonen gibt, die an diesem Datum nett genug waren, um Richtlinienänderungen vorzunehmen (zB America/Bahia_Banderas , America/Hermosillo ). Wenn JVM eine dieser Zonen ist, kann ein Programm, das JDBC verwendet, bestimmte TIME Werte nicht abrufen.

Eine Nichtlösung wäre, die alte API von JDBC abzurufen und in neue Klassen zu konvertieren. Aber das ist generell falsch:

  • ~ resultSet.getTimestamp(col).toLocalDateTime() ~
  • ~ resultSet.getDate(col).toLocalDate() ~
  • ~ resultSet.getTime(col).toLocalTime() ~

Das kompiliert und funktioniert gut, außer dass es keines der oben beschriebenen Probleme löst (sogar das Abrufen des Datums funktioniert nicht, wenn die JVM-Zone Pacific/Apia und das Abrufdatum 2011-12-30 ;)

Nun zur aufkommenden Lösung. ResultSet verfügt über diese weniger beliebte API, mit der Sie den JDBC-Treiber bitten können, den Typ für Sie zu konvertieren:

  • resultSet.getObject(col, LocalDateTime.class) // for TIMESTAMP
  • resultSet.getObject(col, LocalDate.class) // for DATE
  • resultSet.getObject(col, LocalTime.class) // for TIME
  • resultSet.getObject(col, ZonedDateTime.class) // for TIMESTAMP WITH TIME ZONE

Dies scheint mit JDBC-Treibern für PostgreSQL, MySQL, Oracle und H2 zu funktionieren. Und umgeht auf magische Weise die oben beschriebenen Probleme der "Nichtdarstellbarkeit in der JVM-Zone".
Obwohl diese Konvertierung z. B. im SQL Server-Treiber noch nicht implementiert ist, denke ich, dass dies _die_ Standardzuordnung für Java Time-Klassen sein könnte, die von JDBI ausgeliefert werden.

Notiz:
Die JDBC 4.2-Spezifikation schreibt nicht vor, dass ein Treiber dies implementieren muss. Die Spezifikation erfordert jedoch, dass PreparedStatement.setObject und RowSet.setObject Instanzen der Java Time-Klassen akzeptieren und korrekt behandeln, sodass Treiber diese Klassen sowieso explizit unterstützen müssen.

Das ist cool! Meine Hauptsorge ist, dass sich der Wechsel zu diesem Ansatz als Rückschritt für Benutzer manifestieren könnte, die esoterische Treiber verwenden. Aber vielleicht könnten wir mit entsprechenden Nachrichten in den Versionshinweisen diese kleine, technisch bahnbrechende Änderung im Namen von "The Right Way" vornehmen ...

@stevenschlansker du hast recht. Ich denke, JDBI könnte liefern

  • optionaler Satz von Zuordnungen, die ein Benutzer anschließen kann, um das ursprüngliche Verhalten wiederherzustellen
  • einige entsprechende Kommentare in den Versionshinweisen (oder sogar eine größere Versionserweiterung)

Bleiben wir bei einer Nebenversion, wir haben gerade 3 veröffentlicht, und dies ist nur eine bahnbrechende Änderung, wenn Sie es falsch halten ... ;)

Nur um wiederzugeben, was ich höre:

  • Verschieben Sie die vorhandenen integrierten java.time-Mapper in ein separates Plugin (ich mag YoloTimePlugin )
  • Fügen Sie stattdessen neue integrierte Mapper hinzu, die ResultSet.getObject(column, type) anstatt von java.sql-Typen zu konvertieren.
  • Dokumentieren Sie die Scheiße dieser bahnbrechenden Änderung in den Versionshinweisen: Erklären Sie die Auswirkungen dieser Änderung und welche Datenbankanbieter betroffen sind und was Benutzer tun müssen, um Probleme zu mindern

Ich kann dahinter kommen.

Die Frage zum Binden dieser Datums-/Uhrzeitobjekte haben wir jedoch immer noch nicht beantwortet. Alles, was wir an der Zuordnung von Ergebnissen _aus_ der Datenbank ändern, muss so gespiegelt werden, wie wir Datums-/Uhrzeitargumente _in_ SQL-Anweisungen binden.

Alles, was wir an der Zuordnung von Ergebnissen aus der Datenbank ändern, muss in der Art und Weise gespiegelt werden, wie wir Datums-/Uhrzeitargumente in SQL-Anweisungen einbinden.
@qualidafial , sehr gute Frage. Ich habe das nicht getestet. Dies wird ausdrücklich von der JDBC 4.2-Spezifikation abgedeckt, also _sollte einfach funktionieren™_.

Dies wird ausdrücklich von der JDBC 4.2-Spezifikation abgedeckt, also _sollte einfach funktionieren™_.

Dies setzt voraus, dass die JDBC-Treiberimplementierer die Spezifikation perfekt befolgen. Ich habe noch keine JDBC-Treiberimplementierung ohne Fehler gefunden.

Ich habe das Gefühl, dass es zu umständlich wäre, Plugins mit Mappern für jede Datenbank und sogar ihre verschiedenen Versionen bereitzustellen, die unterschiedliche Unterstützung für Datentypen haben. Vielleicht könnte ein einfacherer Ansatz funktionieren: Sie beginnen mit einer Jdbi-Instanz ohne vorinstallierte Mapper, und das Kernartefakt bietet eine Reihe verschiedener Mapper, die Sie manuell zur Installation auswählen können, von denen einige unterschiedliche Logiken haben, um dieselben Datentypen zu verarbeiten - get/ setObject, get/setX, Konvertierung in einen anderen Typ usw. Sie müssen selbst herausfinden, welche Mapper für Ihre Datenbank (Version) und Anwendungslogik am besten geeignet sind, und mithilfe von Unit-Tests dies in Schach halten.

Das mache ich im Grunde sowieso schon jetzt in meinem Projekt. In Jdbi sind einige Mapper vorinstalliert, die nicht mit meiner Datenbank funktionieren und ich brauche sie im Moment nicht Implementierungen (siehe unten).

Dies wäre eine Lösung für diejenigen, die gerne mit ihrer DB intim werden, um sicherzustellen, dass alles absolut funktioniert, und würde nichts für Leute ändern, die etwas an Just Werk™ wollen (sofern dies tatsächlich der Fall ist):

  • Fügen Sie eine Methode zu Jdbi-Instanzen hinzu, um alle ihre Mapper/Argumente zu löschen (sauberer Slate)
  • Stellen Sie die aktuellen integrierten Mapper/Arg-Impls bereit, damit wir sie manuell installieren können
  • Fügen Sie dem Kernartefakt weiterhin alternative Mapper-Impls hinzu, wenn die Nachfrage nach ihnen steigt, und lassen Sie die Leute sie selbst installieren, indem Sie alles wie unten beschrieben generieren, was möglich ist

Auf diese Weise habe ich es geschafft ... viel zu viele Punkte im hsqldb-Treiber zu finden, an denen sie von ihren eigenen Spezifikationen abweichen (in der Quelle gemeldet und behoben, immer noch darauf warten, dass sie endlich ein aktualisiertes Artefakt veröffentlichen) und funktionierte um diese Unvollkommenheiten zu umgehen, indem ich die funktionierende Zuordnungslogik selbst finde.

// I want strings handled differently
<strong i="13">@Component</strong>
public class CleanStringArgumentFactory extends AbstractArgumentFactory<String> {
    protected CleanStringArgumentFactory() {
        super(Types.VARCHAR);
    }

    <strong i="14">@Override</strong>
    protected Argument build(String value, ConfigRegistry config) {
        return (position, statement, ctx) -> statement.setString(position, StringUtils.trimToNull(value));
    }
}
// no need for jdbi's built-in logic
<strong i="17">@Component</strong>
public class SetObjectArgumentFactory implements ArgumentFactory {
    private static final Set<Type> SUPPORTED = ImmutableSet.of(UUID.class, LocalDateTime.class);

    <strong i="18">@Override</strong>
    public Optional<Argument> build(Type type, Object value, ConfigRegistry config) {
        return SUPPORTED.contains(type)
            ? Optional.of(new LoggableArgument(value, (position, statement, context) -> statement.setObject(position, value)))
            : Optional.empty();
    }
}
// these built-ins don't work and I don't need them anyway
<strong i="21">@Component</strong>
public class UnsupportedArgumentFactory implements ArgumentFactory {
    private static final Set<Type> UNSUPPORTED = ImmutableSet.of(ZonedDateTime.class, OffsetDateTime.class, OffsetTime.class);

    <strong i="22">@Override</strong>
    public Optional<Argument> build(Type type, Object value, ConfigRegistry config) {
        if (UNSUPPORTED.contains(type)) {
            throw new UnsupportedOperationException(type.getTypeName() + " is not supported at the moment");
        } else {
            return Optional.empty();
        }
    }
}
// voodoo
<strong i="25">@Inject</strong>
    public JdbiConfiguration(
        @Named("dataSource") DataSource dataSource,
        Set<ArgumentFactory> arguments,
        Set<ColumnMapper> mappers,
        Set<ColumnMapperFactory> mapperFactories
    ) {
        jdbi = Jdbi.create(dataSource);
        jdbi.clearMappings();

        jdbi.installPlugin(new SqlObjectPlugin());

        arguments.forEach(jdbi::registerArgument);
        mapperFactories.forEach(jdbi::registerColumnMapper);
        mappers.forEach(jdbi::registerColumnMapper);

        // ...

        // Jdbi instance fine-tuned for my exact database and demands, without surprises and at my own responsibility

Howbouda? Sie können beispielsweise eine SetObjectArgumentFactory bereitstellen, die mit einer Reihe von Klassen initialisiert werden muss, für die sie aktiviert werden soll, und allen möglichen Variationen der Zuordnungslogik für viele Datentypen, mit einem gegebenenfalls konfigurierbaren Verhalten. Alle glücklich. Es erfordert einige Arbeit vom Endbenutzer, aber ich fühle mich gut zu wissen, dass jdbi genau das tut, was ich will und was meine Datenbank unterstützt.

Ich habe das Gefühl, dass es zu umständlich wäre, Plugins mit Mappern für jede Datenbank und sogar ihre verschiedenen Versionen bereitzustellen, die unterschiedliche Unterstützung für Datentypen haben.

Ich würde gerne Plugins für viele Datenbankanbieter haben. Kommen Sie eins, kommen Sie alle: Wenn Ihre Datenbank einige Anpassungen benötigt / möchte, um Jdbi an die Eigenheiten des Datenbankherstellers oder seines JDBC-Treibers anzupassen, möchten wir davon erfahren. Oder noch besser, wir wollen Pull Requests! :)

Bonuspunkte, wenn Ihre Datenbank direkt von TravisCI unterstützt wird, damit wir tatsächlich Tests damit durchführen können: https://docs.travis-ci.com/user/database-setup/

Zu Ihrem "unbeschriebenen Vorschlag" habe ich nur geringfügige Einwände:

  • Ich würde die Methode clearMappings() wahrscheinlich direkt auf die Konfigurationsklassen RowMappers , ColumnMappers , Arguments und JdbiCollectors anstatt auf Jdbi , und ich würde sie clear() .
  • Ich zögere etwas, die eingebauten Mapper, Argumente und Sammler öffentlich zu machen. Einige von ihnen haben seltsame Namen oder Designs, mit denen wir durchkommen, weil sie intern sind. Ich würde sie wahrscheinlich umgestalten wollen, bevor ich sie zu einem Teil der API mache.
  • Ich frage mich, ob die leere Tafel wirklich notwendig ist. Alle Registrierungsklassen von Jdbi verwenden den Last-Registered-Wins-Ansatz, sodass es immer möglich ist, das standardmäßige Verhalten zu überschreiben. In diesem Sinne fühlt sich die leere Tafel etwas übertrieben an.

@jdbi/contributors interessiert sich noch jemand dafür?

Ich habe die Idee der leeren Tafel aufgenommen, um zu vermeiden, dass versehentlich ein Standard-Mapper verwendet wird, falls Sie vergessen haben, einen Ihrer Wahl zu registrieren. Ich hätte lieber eine NotImplementedException als eine Standard-Impl. Last-Wins ist schön und alles, aber es gibt keine Möglichkeit zu wissen, welche Sie überstimmen müssen, falls Sie keine wollen.

Es ist nicht so, als ob es weh tut, es zu haben. Wenn die Leute diesen Ansatz nicht wollen, müssen sie die klaren Methoden nicht aufrufen und für sie ändert sich nichts. Es ist nur für diejenigen, die eine fehlerfreie Arbeitsweise bevorzugen.

Ich stimme zu, dass wir nicht nur bestehende Mapper öffentlich machen sollten. Wenn wir uns für eine saubere Slate-Option entscheiden, sollten wir die Mapper und Binder in vernünftige Plugin Blöcke, PrimitivesPlugin , BoxedPrimitivesPlugin , CollectionsPlugin bündeln, was auch immer.

Dann können wir eine neue Factory für das "base" jdbi ohne jegliche Konfiguration hinzufügen und die vorhandenen Factorys so ändern, dass sie diese verwenden und WholeJdbiEnchiladaPlugin hinzufügen.

Ich bin etwas gegen "klar", es sei denn, wir können Fälle aufzeigen, in denen es schwierig ist, es additiv zu erstellen - fühlt sich für mich wie ein Code-Geruch an.

Ich bin etwas gegen "klar", es sei denn, wir können Fälle aufzeigen, in denen es schwierig ist, es additiv zu erstellen - fühlt sich für mich wie ein Code-Geruch an.

Nun, wenn Sie eine separate jdbi-Factory ohne Vorkonfiguration hinzufügen, ist es nicht schwierig, sie additiv zu erstellen, sodass wir in der Tat kein clear() benötigen.

Richtig, ich denke, wir sind uns hier einig, ich habe nur meine Präferenz ausgedrückt, eine neue "saubere" Factory-Methode gegenüber einem clear() Stil hinzuzufügen.

Also, löst dies dann alle Probleme? Ich persönlich finde den Plan ziemlich sexy.

  • make Jdbi No-Defaults (wirft für so ziemlich alles Ausnahmen aus)
  • alle vorhandenen Mapper und Binder (und tx-Handler usw.) steckbar machen ( PrimitivesPlugin , BoxedPrimitivesPlugin , usw.), als Plugin-Bundles und als einzelne Klassen
  • bieten einige alternative Implementierungen ( UTCJavaTimePlugin vs LocalJavaTimePlugin vs ConvertJavaTimeToUtilDatePlugin , GetObjectMapper.forClasses(Class... cs) , SetObjectArgumentFactory.forClasses(Class... cs) , NullsToDefaultsPrimitivesPlugin vs NullThrowsExceptionPrimitivesPlugin ) und stellen Sie sie auf die gleiche Weise bereit (in Plugins und einzeln), sodass die Leute ihre eigene gewünschte Mapping-Logik zusammenstellen können und nur genau das nehmen, was sie wollen. Hier ist möglicherweise eine Menge Mapper-Konfiguration erforderlich, z. B. verschiedene Strategien zum Umgang mit illegalen Nullen oder fehlenden Zeitzonen und anderen möglichen Unterschieden
  • Vielleicht erstellen Sie db-spezifische Bundle-Plugins, damit Benutzer mit beliebten Datenbanken + Versionen mit einer No-Config Jdbi und bekannte gute Mapping-Schemata für ihre DB in einer Zeile installieren können ( HsqlDb2_4_0Plugin ), wieder mit Konfigurationsmöglichkeiten für verschiedene Strategien
  • und machen Sie alles abwärtskompatibel, indem Sie einfach die aktuellen Factory-Methoden dazu bringen, die Vorkonfiguration durchzuführen, die wir gerade haben ( BuiltInGenericPreconfigurationPlugin ), neben den Factory-Methoden ohne Konfiguration.

machen Jdbi keine Voreinstellungen

Ich habe keine sehr starke Meinung, aber das klingt alles aus Benutzersicht sehr komplex. Benutzer müssen die verschiedenen möglichen Zuordnungen für die Typen, die sie verwenden möchten, verstehen und eine geeignete auswählen. Dies ist schwierig, besonders wenn Temporals im Spiel sind – es ist wirklich nicht trivial, verschiedene mögliche Optionen zu verstehen.

Benutzer müssen die verschiedenen möglichen Zuordnungen für die Typen, die sie verwenden möchten, verstehen und eine geeignete auswählen

Nein, nur wenn sie wollen. Die bestehenden Factory-Methoden geben weiterhin Jdbi Instanzen mit genau denselben vorinstallierten Mappern aus wie jetzt. Wir werden nur zusätzlich DIY-Config-Factory-Methoden erhalten, und Leute, die sich für diese entscheiden, müssen die Intimitäten des Mappings herausfinden. Es wird auch einen Mittelweg geben, bei dem Sie eine DIY-Instanz erhalten und einfach das YourDbAndVersionPlugin installieren und mit allem, was es tut, rollen. Meine lange Erklärung bezog sich hauptsächlich auf jdbi-Interna und fortgeschrittene Nutzung, nicht auf die Grundlinie.

TLDR: Sie können immer noch Jdbi.create(dataSource) und müssen keine weiteren Schreie darüber machen, die Sie nicht bereits geben. Jemand anderes wählt einfach Jdbi.createBlank(dataSource).install(x).install(y).install(z)...

Ich bin an Bord, aber ich denke nicht, dass wir die bestehenden Fabriken abschaffen sollten. Ich glaube, die meisten Benutzer werden sie weiterhin verwenden, da das Verhalten "out of the box" ziemlich gut ist.

Meinetwegen

@TheRealMarnes Diese ganze Unterhaltung begann mit JSR-310-Datentypen, die nicht direkt von JDBC unterstützt werden.

Ich denke, es besteht Konsens darüber, die fehlerhaften java.time-Mapper und -Argumente zu entfernen und sie in ein Plugin zu stecken, anstatt sie zu integrieren.

Wollen Sie das noch weiterverfolgen?

Nur die java.time? Ein JavaTimePlugin?

Ja, ein Plugin nur für java.time-Typen, aber benannt, um zu kommunizieren, dass die Argumente und Mapper naive, verlustbehaftete Implementierungen sind, wie @findepi beschrieben hat.

SimplisticJavaTimePlugin ?

Damit warte ich, bis meine anderen PRs erledigt sind... Es ist gleichzeitig ein bisschen zu viel.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen