1

I try to update a Postgres daterange. Whatever I try it isn't working. Currently I get

Error:(51, 17) java: reference to set is ambiguous both method set(org.jooq.Field,T) in org.jooq.UpdateSetStep and method set(org.jooq.Field,org.jooq.Field) in org.jooq.UpdateSetStep match

this is my code

    ctx.update(AT_PREFERENCS)
            .set(AT_PREFERENCS.DIRECTION, preferences.direction)
            .set(AT_PREFERENCS.START_END, (Field<Object>) DSL.field("daterange(?, ?)", Object.class, preferences.start, preferences.end))
            .where(AT_PREFERENCS.USER.eq(userId))
            .execute(); 

How can I update daterange with jOOQ?

Angelo.Hannes
  • 1,729
  • 1
  • 18
  • 46

1 Answers1

2

This is due to the very unfortunate Java language design problem (a major flaw in my opinion) documented in this question here. jOOQ should have worked around this problem, but given that jOOQ predates Java 8 and the language design regression was introduced in Java 8, this cannot be fixed in the jOOQ API easily and backwards compatibly right now.

There are several workarounds for this:

Create a data type binding

This might be the most robust solution if you plan on using this range type more often, in case of which you should define a custom data type binding. It's a bit of extra work up front, but once you have that specified, you will be able to write:

.set(AT_PREFERENCES.START_END, new MyRangeType(preferences.start, preferences.end))

Where AT_PREFERENCES.START_END would be a Field<MyRangeType>.

Cast to raw types and bind an unchecked, explicit type variable that isn't Object

This is a quick workaround if you're using this type only once or twice. It has no impact on the runtime, just tweaks the compiler into believing that this is correct.

.<Void>set(
    (Field) AT_PREFERENCES.START_END, 
    (Field) DSL.field("daterange(?, ?)", Object.class, preferences.start, preferences.end))

Cast to raw types and then back to some other Field<T> type

Same as before, but this lets type inference do the job of inferring <Void> for <T>

.set(
    (Field<Void>) (Field) AT_PREFERENCES.START_END, 
    (Field<Void>) (Field) DSL.field("daterange(?, ?)", Object.class, 
                            preferences.start, preferences.end))

Explicitly bind to the "wrong" API method

jOOQ internally handles all method calls in those rare cases where type safety breaks and the "wrong" overload is called. So, you could also simply call this:

.set(
    AT_PREFERENCES.START_END, 
    (Object) DSL.field("daterange(?, ?)", Object.class, 
      preferences.start, preferences.end))

With this cast, only the set(Field<T>, T) method is applicable and you no longer rely on the Java compiler finding the most specific method among the applicable overloads (which no longer works since Java 8).

jOOQ will run an instanceof check on the T argument, to see if it is really of type Field, in case of which it internally re-routes to the intended API method set(Field<T>, Field<T>)

Lukas Eder
  • 211,314
  • 129
  • 689
  • 1,509