Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ForcedType enum with no matching value being converted to last enum value #7076

Closed
maxsumrall opened this issue Jan 16, 2018 · 5 comments
Closed

Comments

@maxsumrall
Copy link

Expected behavior and actual behavior:

When creating a forced type between a Postgres enum type and a Java enum, using the default EnumConverter implementation, if there is not a exact string match between any of the values, then null is mapped to the last value in the Java enum.

This is surprising when a null value in the db gets mapped to a seemingly random Java enum value.

Steps to reproduce the problem:

Create an enum type in postgres and an enum in java, where the values of the enum do not match.
For example in postgres:

CREATE TYPE myenum AS ENUM (
 'VAL',
 'VAL-A',
  'VAL-B'
);

and in java I create an enum

public enum MyEnum 
{
    VAL, 
    VAL_A,
    VAL_B;
}

(Notice that one has dashes and other is underscored)
And then configure a jooq to do a forced enum conversion:

<forcedTypes>
  <forcedType>
  <userType>com.me.MyEnum</userType>
 <converter>
 com.me.EnumConverters.MyEnumConverter
 </converter>
 <types>myenum</types>
 </forcedType>
 </forcedTypes>

With a converter being:

public final class EnumConverters {

    private EnumConverters() {}

    public static final class MyEnumConverter
            extends EnumConverter<Myenum, MyEnum> {
        public MyEnumConverter() {
            super(Myenum.class, MyEnum.class);
        }
    }
}

Then jooq will create a mapping where VAL maps correctly, but for the other two values, it will create a mapping from null to VAL-B. This is because there is no matching value and null is returned from https://github.com/jOOQ/jOOQ/blob/master/jOOQ/src/main/java/org/jooq/tools/Convert.java#L970
And that null is used as the key in: https://github.com/jOOQ/jOOQ/blob/master/jOOQ/src/main/java/org/jooq/impl/EnumConverter.java#L67
This is a problem in cases where the value in the DB is null but it maps to the enum value VAL-B

Versions:

  • jOOQ: 3.10.2
  • Java: 8
  • Database (include vendor): Postgres 9.6
  • JDBC Driver (include name if inofficial driver):
@lukaseder
Copy link
Member

Thanks for your detailed report.

Unfortunately, I have to say that this works "as designed". If there is no exact match between your database enum and your Java enum, and you do not use the generated enums, a converter, or a binding that makes the mapping explicit, then jOOQ cannot reasonably guess that the VAL-A value corresponds to VAL_A.

The underscore _ is generated as a workaround for invalid Java identifier characters, such as -. This could be changed through a generator strategy 1, but it wouldn't help in this particular case.

Maybe your expectation was for this to fail with an exception, and indeed, there's a feature request for jOOQ 4.0 to let jOOQ fail more early in such cases (cannot find it right now).

With these explanations and options (don't map, use a converter or a binding), I'm not sure what's left in your request for us to do...?

@maxsumrall
Copy link
Author

maxsumrall commented Jan 16, 2018 via email

@maxsumrall
Copy link
Author

Just to clarify, I don't expect it to match "VAL-A" to "VAL_A", but in this case if the the enum in the DB had only one value "FOO" and in Java your enum only had the value "BAR", it would still map "null" to "BAR", which is where I think an exception would be more appropriate.

@lukaseder
Copy link
Member

Looking into this now. A simple test case reproduces the problem:

    public enum A { A }
    public enum B { A, B }

    public static final class ABConverter extends EnumConverter<A, B> {
        public ABConverter() {
            super(A.class, B.class);
        }
    }

    @Test
    public void testMismatchingEnumConverter() {
        ABConverter c = new ABConverter();
        assertEquals(B.A, c.from(A.A));
        assertNull(c.from(null)); // This fails

        assertEquals(A.A, c.to(B.A));
        assertNull(c.to(B.B));
        assertNull(c.to(null));
    }

The failing line converts null to B.B instead of null

@lukaseder lukaseder added this to To do in 3.18 Other improvements via automation Nov 24, 2022
lukaseder added a commit that referenced this issue Nov 24, 2022
lukaseder added a commit that referenced this issue Nov 24, 2022
lukaseder added a commit that referenced this issue Nov 24, 2022
@lukaseder
Copy link
Member

Fixed in jOOQ 3.18.0, 3.17.6 (#14292), and 3.16.12 (#14293)

3.18 Other improvements automation moved this from To do to Done Nov 24, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
No open projects
Development

No branches or pull requests

2 participants