jpa-spec
  1. jpa-spec
  2. JPA_SPEC-73

Parameterized AttributeConverter and/or AttributeConverter metadata access

    Details

    • Type: Improvement Improvement
    • Status: Open
    • Priority: Major Major
    • Resolution: Unresolved
    • Labels:
      None

      Description

      It would be good if we were able to parameterize AttributeConverter instances and/or have access to property metadata within an AttributeConverter. This way we are able to reuse AttributeConverter code instead of building similar ones or even supply further required context information. An example:

      Quite often we have to deal with ancient DB schemas, and just recently we started to migrate a large Cobol application to Java. We are unable to change the content of the database, and because of Cobol with have to support fixed width string columns containing left padded data. A 5 digit fixed width column will represent 1 as '00001' and 100 as '00100'. Nothing we can change here. Unless I am mistaken I have to create a dedicated converter for every required fixed length ending up with an LeadingZeroTwoDigitAttributeConverter, LeadingZeroFiveDigitAttributeConverter and so on.

      Right now it seems the JPA spec does not define wether there is one converter instance per persistent property or just a global one (which would be OK by current spec requirements). I would propose that parameterized converter instances are bound to property fields in order to support parameter evaluation during JPA provider startup.

      I believe we need access to both basic attribute information and optionally supplied converter attributes. The following example would assume access to the leading pad char, the length attribute and wether the attribute is nullable or not. (in my current project I have to store an empty string for null values in the database).

      @Convert(converter = LeadingDigitAttributeConverter.class, metaData="padChar=0" )
      @Column(name = "ACOLUM", length=5, nullable = false)

      If you believe there is no need to support something like that: Unfortunately we are in the middle of migrating quite a few very very old applications to Java, and we can't change that stuff. And there is more to come.

        Activity

        Hide
        isk0001y added a comment -

        Such a parameterized AttributeConverter may also be of help when one is creating converter for hundreds of enums.
        In our project we have approx. 260 enums, which implement a simple interface.

        I can use the AttributeConverter to persist any enum implementing that interface, by just calling "getFoo()"; assuming getFoo() will return a basic type like string, the direction to the database is problem-free.
        However, since I cannot parameterize the Converter, and I have no access to the Property-Type in the entity the converter is about to be applied, I cannot reversely find out the Enum-Class whose foo i had persisted.
        This end me in creating over 260 Converters alongside 260 enums.

        Both eclipselink and hibernate provide have solutions for this. Eclipselink allows me to use their "Converter" infrastructure to create Converters with a special "initialize" method that allows me to access the entity property being converted. Hibernate allows me to create "UserDefinedTypes" like "UserType", where the @Type annotation takes an array of @Parameters to configure the converter. Both techniques result in me creating only ONE converter, but any entity class is then dependent on the concrete JPA provider through imports. This cannot be what you guys want

        If I already must stick to one JPA provider, then I completely can skip using jpa at all, and stay incompatible.

        Show
        isk0001y added a comment - Such a parameterized AttributeConverter may also be of help when one is creating converter for hundreds of enums. In our project we have approx. 260 enums, which implement a simple interface. I can use the AttributeConverter to persist any enum implementing that interface, by just calling "getFoo()"; assuming getFoo() will return a basic type like string, the direction to the database is problem-free. However, since I cannot parameterize the Converter, and I have no access to the Property-Type in the entity the converter is about to be applied, I cannot reversely find out the Enum-Class whose foo i had persisted. This end me in creating over 260 Converters alongside 260 enums. Both eclipselink and hibernate provide have solutions for this. Eclipselink allows me to use their "Converter" infrastructure to create Converters with a special "initialize" method that allows me to access the entity property being converted. Hibernate allows me to create "UserDefinedTypes" like "UserType", where the @Type annotation takes an array of @Parameters to configure the converter. Both techniques result in me creating only ONE converter, but any entity class is then dependent on the concrete JPA provider through imports. This cannot be what you guys want If I already must stick to one JPA provider, then I completely can skip using jpa at all, and stay incompatible.
        Hide
        tomdcc added a comment -

        We have need of this as well - we'd like to convert enum attributes to specific string representations in the database, and with the current spec we have to create a converter per enum, rather than e.g. having the enum classes implement an interface to make the required string available and use a single converter.

        Hibernate has parameters that you can pass to their converter types which is a workaround for this, but we're not using Hibernate for this project and in any case it's pretty ugly to have to do that for every column.

        Making the metamodel attribute available to the converter would be perfect, as it could then grab the attribute type. The nice thing about that approach, too, is that if someone wants to pass extra info in to the converter that isn't available in the normal JPA model, they can create a custom annotation and the converter can call attribute.getJavaMember() and look for annotations, and the info is right with all the other metadata for the attribute.

        Show
        tomdcc added a comment - We have need of this as well - we'd like to convert enum attributes to specific string representations in the database, and with the current spec we have to create a converter per enum, rather than e.g. having the enum classes implement an interface to make the required string available and use a single converter. Hibernate has parameters that you can pass to their converter types which is a workaround for this, but we're not using Hibernate for this project and in any case it's pretty ugly to have to do that for every column. Making the metamodel attribute available to the converter would be perfect, as it could then grab the attribute type. The nice thing about that approach, too, is that if someone wants to pass extra info in to the converter that isn't available in the normal JPA model, they can create a custom annotation and the converter can call attribute.getJavaMember() and look for annotations, and the info is right with all the other metadata for the attribute.
        Hide
        frenchc added a comment -

        Sounds good to me.

        Show
        frenchc added a comment - Sounds good to me.
        Hide
        c.beikov added a comment - - edited

        I agree that metadata is needed but I guess it would be easier to just let the converter instance know about the metamodel Attribute instance or something simialar.
        You can define your own annotations that can be used for configuration purposes of the converter. Through the metamodel you can get your hands on those values.
        I propose that you can either inject that instance or with java 8 default methods around, introduce a new default method "void init(javax.persistence.metamodel.Attribute)" in the AttributeConverter.

        Show
        c.beikov added a comment - - edited I agree that metadata is needed but I guess it would be easier to just let the converter instance know about the metamodel Attribute instance or something simialar. You can define your own annotations that can be used for configuration purposes of the converter. Through the metamodel you can get your hands on those values. I propose that you can either inject that instance or with java 8 default methods around, introduce a new default method "void init(javax.persistence.metamodel.Attribute)" in the AttributeConverter.

          People

          • Assignee:
            Unassigned
            Reporter:
            frenchc
          • Votes:
            4 Vote for this issue
            Watchers:
            3 Start watching this issue

            Dates

            • Created:
              Updated: