Uploaded image for project: 'WildFly'
  1. WildFly
  2. WFLY-18275

Hibernate can't access Jackson

XMLWordPrintable

      The Hibernate module does not have access to the Jackson module in modules/system/layers/base/org/hibernate/main/module.xml.

      This is a problem when using Hibernates JSON Mapping feature, which uses Jackson: https://docs.jboss.org/hibernate/orm/6.2/userguide/html_single/Hibernate_User_Guide.html#basic-mapping-json

      Issue when querying entities

      When you query an entity that has a field annotated with @JdbcTypeCode(SqlTypes.JSON) you get the following exception, because Hibernate cannot see the Jackson classes:

      org.hibernate.HibernateException: Could not find a FormatMapper for the JSON format, which is required for mapping JSON types. JSON FormatMapper configuration is automatic, but requires that you have either Jackson or a JSONB implementation like Yasson on the class path.
      	at org.hibernate@6.2.1.Final//org.hibernate.internal.FastSessionServices.getJsonFormatMapper(FastSessionServices.java:387)
      	at org.hibernate@6.2.1.Final//org.hibernate.type.descriptor.jdbc.JsonJdbcType.fromString(JsonJdbcType.java:86)
      	at org.hibernate@6.2.1.Final//org.hibernate.type.descriptor.jdbc.JsonJdbcType$2.doExtract(JsonJdbcType.java:140)
      	at org.hibernate@6.2.1.Final//org.hibernate.type.descriptor.jdbc.BasicExtractor.extract(BasicExtractor.java:44)
      	at org.hibernate@6.2.1.Final//org.hibernate.sql.results.jdbc.internal.JdbcValuesResultSetImpl.readCurrentRowValues(JdbcValuesResultSetImpl.java:262)
      	at org.hibernate@6.2.1.Final//org.hibernate.sql.results.jdbc.internal.JdbcValuesResultSetImpl.advance(JdbcValuesResultSetImpl.java:243)
      	at org.hibernate@6.2.1.Final//org.hibernate.sql.results.jdbc.internal.JdbcValuesResultSetImpl.processNext(JdbcValuesResultSetImpl.java:84)
      	at org.hibernate@6.2.1.Final//org.hibernate.sql.results.jdbc.internal.AbstractJdbcValues.next(AbstractJdbcValues.java:29)
      	at org.hibernate@6.2.1.Final//org.hibernate.sql.results.internal.RowProcessingStateStandardImpl.next(RowProcessingStateStandardImpl.java:62)
      	at org.hibernate@6.2.1.Final//org.hibernate.sql.results.spi.ListResultsConsumer.consume(ListResultsConsumer.java:198)
      	at org.hibernate@6.2.1.Final//org.hibernate.sql.results.spi.ListResultsConsumer.consume(ListResultsConsumer.java:33)
      	at org.hibernate@6.2.1.Final//org.hibernate.sql.exec.internal.JdbcSelectExecutorStandardImpl.doExecuteQuery(JdbcSelectExecutorStandardImpl.java:362)
      	at org.hibernate@6.2.1.Final//org.hibernate.sql.exec.internal.JdbcSelectExecutorStandardImpl.executeQuery(JdbcSelectExecutorStandardImpl.java:168)
      	at org.hibernate@6.2.1.Final//org.hibernate.sql.exec.internal.JdbcSelectExecutorStandardImpl.list(JdbcSelectExecutorStandardImpl.java:93)
      	at org.hibernate@6.2.1.Final//org.hibernate.sql.exec.spi.JdbcSelectExecutor.list(JdbcSelectExecutor.java:31)
      	at org.hibernate@6.2.1.Final//org.hibernate.query.sqm.internal.ConcreteSqmSelectQueryPlan.lambda$new$0(ConcreteSqmSelectQueryPlan.java:109)
      	at org.hibernate@6.2.1.Final//org.hibernate.query.sqm.internal.ConcreteSqmSelectQueryPlan.withCacheableSqmInterpretation(ConcreteSqmSelectQueryPlan.java:302)
      	at org.hibernate@6.2.1.Final//org.hibernate.query.sqm.internal.ConcreteSqmSelectQueryPlan.performList(ConcreteSqmSelectQueryPlan.java:243)
      	at org.hibernate@6.2.1.Final//org.hibernate.query.sqm.internal.QuerySqmImpl.doList(QuerySqmImpl.java:521)
      	at org.hibernate@6.2.1.Final//org.hibernate.query.spi.AbstractSelectionQuery.list(AbstractSelectionQuery.java:367)
      	at org.hibernate@6.2.1.Final//org.hibernate.query.sqm.internal.QuerySqmImpl.list(QuerySqmImpl.java:1084)
      	at org.hibernate@6.2.1.Final//org.hibernate.query.Query.getResultList(Query.java:119)
      

      Issue when using a custom JSON FormatMapper

      If you try to supply a custom JSON-FormatMapper (as described in https://docs.jboss.org/hibernate/orm/6.2/userguide/html_single/Hibernate_User_Guide.html#misc-options) by adding the following to your persistence.xml:

      <property name="hibernate.type.json_format_mapper" value="MyJsonFormatMapper" />
      

      Then the deployment fails with the following error:

      {"WFLYCTL0062: Composite operation failed and was rolled back. Steps that failed:" => {"Operation step-2" => {"WFLYCTL0080: Failed services" => {"jboss.persistenceunit.\"my-app.war#MY_PERSISTENCE_UNIT\"" => "java.lang.NoClassDefFoundError: com/fasterxml/jackson/core/JsonProcessingException
          Caused by: java.lang.NoClassDefFoundError: com/fasterxml/jackson/core/JsonProcessingException
          Caused by: java.lang.ClassNotFoundException: com.fasterxml.jackson.core.JsonProcessingException from [Module \"org.hibernate\" version 6.2.1.Final from local module loader @331acdad (finder: local module finder @41d426b5 (roots: wildfly\\modules,wildfly\\modules\\system\\layers\\base))]"}}}}
      

      Here is the class MyJsonFormatMapper for reference:

      import org.hibernate.type.descriptor.WrapperOptions;
      import org.hibernate.type.descriptor.java.JavaType;
      import org.hibernate.type.format.FormatMapper;
      import org.hibernate.type.format.jackson.JacksonJsonFormatMapper;
      import com.fasterxml.jackson.databind.ObjectMapper;
      
      public class MyJsonFormatMapper implements FormatMapper {
        private final FormatMapper delegate = new JacksonJsonFormatMapper(new ObjectMapper());
      
        @Override
        public <T> T fromString(CharSequence charSequence, JavaType<T> javaType, WrapperOptions wrapperOptions) {
          return delegate.fromString(charSequence, javaType, wrapperOptions);
        }
      
        @Override
        public <T> String toString(T value, JavaType<T> javaType, WrapperOptions wrapperOptions) {
          return delegate.toString(value, javaType, wrapperOptions);
        }
      }
      

      Proposed solution for JSON

      I can resolve the issue by adding the following two dependencies to the file modules/system/layers/base/org/hibernate/main/module.xml:

      <module name="com.fasterxml.jackson.core.jackson-core"/>
      <module name="com.fasterxml.jackson.core.jackson-databind"/>
      

      Issue when using a custom XML FormatMapper

      If you try to supply a custom XML-FormatMapper (as described in https://docs.jboss.org/hibernate/orm/6.2/userguide/html_single/Hibernate_User_Guide.html#misc-options) by adding the following to your persistence.xml:

      <property name="hibernate.type.xml_format_mapper" value="MyXmlFormatMapper" />
      

      Then the deployment fails with the following error:

      {"WFLYCTL0062: Composite operation failed and was rolled back. Steps that failed:" => {"Operation step-2" => {"WFLYCTL0080: Failed services" => {"jboss.persistenceunit.\"my-app.war#MY_PERSISTENCE_UNIT\"" => "java.lang.NoClassDefFoundError: com/fasterxml/jackson/dataformat/xml/XmlMapper
          Caused by: java.lang.NoClassDefFoundError: com/fasterxml/jackson/dataformat/xml/XmlMapper
          Caused by: java.lang.ClassNotFoundException: com.fasterxml.jackson.dataformat.xml.XmlMapper from [Module \"org.hibernate\" version 6.2.1.Final from local module loader @22295ec4 (finder: local module finder @5adb0db3 (roots: wildfly\\modules,wildfly\\modules\\system\\layers\\base))]"}}}}
      

      Here is the class MyXmlFormatMapper for reference:

      import org.hibernate.type.descriptor.WrapperOptions;
      import org.hibernate.type.descriptor.java.JavaType;
      import org.hibernate.type.format.FormatMapper;
      import org.hibernate.type.format.jackson.JacksonXmlFormatMapper;
      
      public class MyXmlFormatMapper implements FormatMapper {
        private final FormatMapper delegate = new JacksonXmlFormatMapper();
      
        @Override
        public <T> T fromString(CharSequence charSequence, JavaType<T> javaType, WrapperOptions wrapperOptions) {
          return delegate.fromString(charSequence, javaType, wrapperOptions);
        }
      
        @Override
        public <T> String toString(T value, JavaType<T> javaType, WrapperOptions wrapperOptions) {
          return delegate.toString(value, javaType, wrapperOptions);
        }
      }
      

      This error occurs even when the war file contains jackson-dataformat-xml-2.14.2.jar in it's WEB-INF/lib directory so I suspect that the hibernate module does not gain access to user provided libraries. I suspect that this may also be a problem, if you use a FormatMapper for JSON that uses some library other than Jackson. Maybe the FormatMapper class is loaded with the hibernate module classloader but shoud be loaded by the application classloader? I don't know how WildFly loads classes, this is just a thought.

      Since there is no module com.fasterxml.jackson.dataformat.jackson-dataformat-xml I didn't find a fix to use a FormatMapper for XML, but luckily I only need JSON support for now. Still it would be great if I didn't have to manually patch the WildFly installation whenever a new version comes out.

      Closing thoughts

      Even if adding the dependencies to modules/system/layers/base/org/hibernate/main/module.xml does not fix the problem with a custom XML-FormatMapper I think it would still be worth it to include the two lines in the next WildFly release to at least support JSON via Jackson until a full fix is found.

            smarlow1@redhat.com Scott Marlow
            adrodoc Adrodoc 55 (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated:
              Resolved: