62

I'm working on a Spring JPA Application, using MySQL as database. I ensured that all spring-jpa libraries, hibernate and mysql-connector-java is loaded.

I'm running a mysql 5 instance. Here is a excerpt of my application.properties file:

spring.jpa.show-sql=false
spring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.database-platform=org.hibernate.dialect.MySQL5Dialect

spring.datasource.url=jdbc:mysql://localhost/mydatabase
spring.datasource.username=myuser
spring.datasource.password=SUPERSECRET
spring.datasource.driverClassName=com.mysql.jdbc.Driver

When executing an integration test, spring startsup properly but fails on creating the hibernate SessionFactory, with the exception:

org.hibernate.MappingException: No Dialect mapping for JDBC type: 1111

I think my dialects should be Mysql5Dialect, I also tried the one explicitly stating InnoDB, and the two dialect options which don't indicate the version 5. But I always end up with the same 'No Dialect mapping for JDBC type: 1111' message. My application.properties file resides in the test/resources source folder. It is recognized by the JUnit Test runner (I previously got an exception because of an typo in it).

Are the properties I'm setting wrong? I couldn't find some official documentation on these property names but found a hint in this stackoverflow answer: https://stackoverflow.com/a/25941616/1735497

Looking forward for your answers, thanks!

BTW The application is already using spring boot.

Community
  • 1
  • 1
SakeSushiBig
  • 1,481
  • 2
  • 14
  • 20
  • 3
    The error message means one column returns data in a type which cannot be mapped. `No Dialect mapping for JDBC type: 1111` indicates java.sql.Types.OTHER`. What column types do you select from the table? – SubOptimal Jan 28 '15 at 13:00
  • 1
    Oh, thanks. I thought this means the dialect type ... Yeah I like to use UUIDs as IDs and we previously always worked with postgres, which has a UUID column type. So we could just say @Type(type="pg-uuid"); I don't think mysql has an UUID column type though – SakeSushiBig Jan 28 '15 at 13:02
  • Just found out it is very similar to postgres: apply @Type(type="uuid-char") annotation to the id attribute. – SakeSushiBig Jan 28 '15 at 13:07
  • 1
    I have this problem if put on SELECT statement a json field. I use PostgresSQL and a custom hibernate field Type for json type. – giaffa86 Mar 17 '17 at 17:10

21 Answers21

48

I got the same error because my query returned a UUID column. To fix that I returned the UUID column as varchar type through the query like "cast(columnName as varchar)", then it worked.

Example:

public interface StudRepository extends JpaRepository<Mark, UUID> {

    @Modifying
    @Query(value = "SELECT Cast(stuid as varchar) id, SUM(marks) as marks FROM studs where group by stuid", nativeQuery = true)
    List<Student> findMarkGroupByStuid();

    public static interface Student(){
        private String getId();
        private String getMarks();
    }
}
biniam
  • 8,099
  • 9
  • 49
  • 58
Ramya
  • 581
  • 4
  • 3
36

Here the answer based on the comment from SubOptimal:

The error message actually says that one column type cannot be mapped to a database type by hibernate. In my case it was the java.util.UUID type I use as primary key in some of my entities. Just apply the annotation @Type(type="uuid-char") (for postgres @Type(type="pg-uuid"))

Amir Azizkhani
  • 1,662
  • 17
  • 30
SakeSushiBig
  • 1,481
  • 2
  • 14
  • 20
  • 3
    If you get the exception only in test environment on HSQLDB - take a look at http://stackoverflow.com/questions/1007176/using-different-hibernate-user-types-in-different-situations – Ilya Serbis Mar 23 '16 at 15:48
  • 1
    I agree with Lu55 . You should not add the @Type annotation until it is really necessary. But I don't really agree with the solutions provided in the linked issue (maybe they are just too old?). Therefore I create a post with my own solution: http://stackoverflow.com/questions/1007176/using-different-hibernate-user-types-in-different-situations/40828806#40828806 – Tim Nov 27 '16 at 12:13
  • 1
    Or alternatively in your query string you can also do a Casting to Varchar like so: CAST( table_name.column_name as VARCHAR) AS table_name – absin Mar 07 '17 at 08:54
22

There is also another common use-case throwing this exception. Calling function which returns void. For more info and solution go here.

Community
  • 1
  • 1
icl7126
  • 5,740
  • 4
  • 53
  • 51
13

I got the same error, the problem here is UUID stored in DB is not converting to object.

I tried applying these annotations @Type(type="uuid-char") (for postgres @Type(type="pg-uuid") but it didn't work for me.

This worked for me. Suppose you want id and name from a table with a native query in JPA. Create one entity class like 'User' with fields id and name and then try converting object[] to entity we want. Here this matched data is list of array of object we are getting from query.

@Query( value = "SELECT CAST(id as varchar) id, name from users ", nativeQuery = true)

public List<Object[]> search();

public class User{
   private UUID id;
   private String name;
}


List<User> userList=new ArrayList<>();

for(Object[] data:matchedData){
        userList.add(new User(UUID.fromString(String.valueOf(data[0])),
                String.valueOf(data[1])));

    }

Suppose this is the entity we have

Supreet Singh
  • 882
  • 12
  • 9
11

Please Check if some Column return many have unknow Type in Query .

eg : '1' as column_name can have type unknown

and 1 as column_name is Integer is correct One .

This thing worked for me.

jaskirat Singh
  • 696
  • 1
  • 8
  • 17
  • 3
    I had a native query with a my own SqlResultMapping and this was the problem, fixed it by adding a cast to the query ''CAST('staticstring' AS varchar(50)) as columnmappingname – dwana Aug 07 '17 at 10:50
  • Yes, you have to use this CAST function within your QUERY to typecast into your appropriate DataType. – jaskirat Singh Jul 02 '18 at 09:24
10

Finding the column that triggered the issue

First, you didn't provide the entity mapping so that we could tell what column generated this problem. For instance, it could be a UUID or a JSON column.

Now, you are using a very old Hibernate Dialect. The MySQL5Dialect is meant for MySQL 5. Most likely you are using a newer MySQL version.

So, try to use the MySQL8Dialect instead:

spring.jpa.database-platform=org.hibernate.dialect.MySQL8Dialect

Adding non-standard types

In case you got the issue because you are using a JSON column type, try to provide a custom Hibernate Dialect that supports the non-standard Type:

public class MySQL8JsonDialect
        extends MySQL8Dialect{
 
    public MySQL8JsonDialect() {
        super();
        this.registerHibernateType(
            Types.OTHER, JsonStringType.class.getName()
        );
    }
}

And use the custom Hibernate Dialect:

<property
    name="hibernate.dialect"
    value="com.vladmihalcea.book.hpjp.hibernate.type.json.MySQL8JsonDialect"
/>

If you get this exception when executing SQL native queries, then you need to pass the type via addScalar:

JsonNode properties = (JsonNode) entityManager
.createNativeQuery(
    "SELECT properties " +
    "FROM book " +
    "WHERE isbn = :isbn")
.setParameter("isbn", "978-9730228236")
.unwrap(org.hibernate.query.NativeQuery.class)
.addScalar("properties", JsonStringType.INSTANCE)
.getSingleResult();
 
assertEquals(
    "High-Performance Java Persistence",
    properties.get("title").asText()
);
Saikat
  • 14,222
  • 20
  • 104
  • 125
Vlad Mihalcea
  • 142,745
  • 71
  • 566
  • 911
  • Adding dialect didn't help, unfortunately only Unit test build is failing in my case. (UT has local db) @Vlad Mihalcea – Code Name Jack Jan 19 '21 at 04:54
  • As long as you run the integration tests on MySQL in a Docker container, everything will work like a charm. If you use in-memory DBs, like H2 or HSQLDB, it will not work. – Vlad Mihalcea Jan 19 '21 at 06:15
  • Ya using, in memory db here, got past that error, now facing another. `Caused by: org.hibernate.exception.SQLGrammarException: could not prepare statement` Will try to fix this too. – Code Name Jack Jan 19 '21 at 06:41
3

Sometimes when you call sql procedure/function it might be required to return something. You can try returning void: RETURN; or string (this one worked for me): RETURN 'OK'

Klapsa2503
  • 829
  • 10
  • 33
3

If you have native SQL query then fix it by adding a cast to the query.

Example:

CAST('yourString' AS varchar(50)) as anyColumnName

In my case it worked for me.

Bharti Rawat
  • 1,949
  • 21
  • 32
3

Another simple explanation might be that you're fetching a complex Type (Entity/POJO) but do not specify the Entity to map to:

String sql = "select yourentity.* from {h-schema}Yourentity yourentity";
return entityManager.createNativeQuery(sql).getResultList();

simply add the class to map to in the createNativeQuery method:

return entityManager.createNativeQuery(sql, Yourentity.class).getResultList();
icyerasor
  • 4,973
  • 1
  • 43
  • 52
3

In my case, the issue was Hibernate not knowing how to deal with an UUID column. If you are using Postgres, try adding this to your resources/application.properties:

spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQL9Dialect
Andrei Savin
  • 2,350
  • 4
  • 26
  • 40
1

In my case the problem was that, I forgot to add resultClasses attribute when I setup my stored procedure in my User class.

@NamedStoredProcedureQuery(name = "find_email",
                procedureName = "find_email", resultClasses = User.class, //<--I forgot that. 
                parameters = {
                    @StoredProcedureParameter(mode = ParameterMode.IN, name = "param_email", type = String.class)
                }),
GaborH
  • 689
  • 2
  • 11
  • 24
1

This also happens when you are using Hibernate and returning a void function. AT least w/ postgres. It doesnt know how to handle the void. I ended up having to change my void to a return int.

1

If you are using Postgres, check that you don't have a column of type Abstime. Abstime is an internal Postgres datatype not recognized by JPA. In this case, converting to Text using TO_CHAR could help if permitted by your business requirements.

tutak
  • 1,120
  • 1
  • 15
  • 28
  • im facing the same problem as mentioned here. is there an other solution yet? it keeps me from doing asterisk queries. – MavidDeyers May 07 '20 at 12:34
1

if using Postgres

public class CustomPostgreSqlDialect extends PostgreSQL94Dialect{

    @Override
    public SqlTypeDescriptor remapSqlTypeDescriptor(SqlTypeDescriptor sqlTypeDescriptor)
    {
        switch (sqlTypeDescriptor.getSqlType())
        {
        case Types.CLOB:
            return VarcharTypeDescriptor.INSTANCE;
        case Types.BLOB:
            return VarcharTypeDescriptor.INSTANCE;
        case 1111://1111 should be json of pgsql
            return VarcharTypeDescriptor.INSTANCE;
        }
        return super.remapSqlTypeDescriptor(sqlTypeDescriptor);
    }
    public CustomPostgreSqlDialect() {
        super();
        registerHibernateType(1111, "string");
    }}

and use

<prop key="hibernate.dialect">com.abc.CustomPostgreSqlDialect</prop>
Gaurav Jeswani
  • 4,410
  • 6
  • 26
  • 47
  • And if you are using spring, instead of the hibernate.dialect prop mentioned, at the properties file put: `spring.jpa.properties.hibernate.dialect=com.abc.CustomPostgreSqlDialect` – Tonsic Mar 13 '22 at 17:55
0

For anybody getting this error with an old hibernate (3.x) version:

do not write the return type in capital letters. hibernate type implementation mapping uses lowercase return types and does not convert them:

CREATE OR REPLACE FUNCTION do_something(param varchar)
    RETURNS integer AS
$BODY$
...
Anubis
  • 481
  • 4
  • 4
0

This is for Hibernate (5.x) version

Calling database function which return JSON string/object

For this use unwrap(org.hibernate.query.NativeQuery.class).addScalar() methods for the same.

Example as below (Spring & Hibernate):

@PersistenceContext

EntityManager em;

@Override

    public String getJson(String strLayerName) {

        String *nativeQuery* = "select fn_layer_attributes(:layername)";

        return em.createNativeQuery(*nativeQuery*).setParameter("layername", strLayerName).**unwrap(org.hibernate.query.NativeQuery.class).addScalar**("fn_layer_attributes", **new JsonNodeBinaryType()**) .getSingleResult().toString();

    }

RobC
  • 22,977
  • 20
  • 73
  • 80
Ashok Parmar
  • 336
  • 4
  • 4
0

Function or procedure returning void cause some issue with JPA/Hibernate, so changing it with return integer and calling return 1 at the end of procedure may solved the problem.

SQL Type 1111 represents String.

iamfnizami
  • 163
  • 1
  • 8
0

If you are calling EntityManager.createNativeQuery(), be sure to include the resulting java class in the second parameter:

return em.createNativeQuery(sql, MyRecord.class).getResultList()
0

After trying many proposed solutions, including:

it was finally this one that fixed everything with the least amount of changes:

https://gist.github.com/agrawald/adad25d28bf6c56a7e4618fe95ee5a39

The trick is to not have @TypeDef on your class, but instead have 2 different @TypeDef in 2 different package-info.java files. One inside your production code package for your production DB, and one inside your test package for your test H2 DB.

Chris
  • 4,212
  • 5
  • 37
  • 52
  • @VladMihalcea according to the last comment in https://gist.github.com/agrawald/adad25d28bf6c56a7e4618fe95ee5a39 I shouldn't need this fix when using your JsonType. However, I was already using your JsonType (for PostGIS in Production and H2 in my `@SpringDataTest`s), and only the above solution was able to fix it for me. – Chris Apr 28 '22 at 10:50
0

I had the same issue and wasted like 1 hour before I noticed that I use JpaRepository of one entity (let's say Person) to retrive another entity (let's say Order). Hope this helps someone.

0

I had little different issue, I was facing this issue for pagination. When select query was pulling number of records (15) more than pageSize(10) then I was getting below error. -

Details: org.springframework.orm.jpa.JpaSystemException: No Dialect mapping for JDBC type: 1111; nested exception is org.hibernate.MappingException: No Dialect mapping for JDBC type: 1111

Before fixing I made sure -

  1. My Dialect lib is latest
  2. column data types are correct

Fix - added registerHibernateType

@Component
public class JSONBPostgreSQLDialect extends PostgreSQL95Dialect {

    public JSONBPostgreSQLDialect() {
        super();
        registerColumnType(Types.JAVA_OBJECT, JSONBUserType.JSONB_TYPE);
        //This line fixed Dialect mapping errorx
        registerHibernateType(Types.OTHER, String.class.getName());
    }
}

JSONBUserType is custom type created.

@Component
public class JSONBUserType implements UserType, ParameterizedType {

    private static final ClassLoaderService classLoaderService = new ClassLoaderServiceImpl();

    public static final String JSONB_TYPE = "jsonb";
    public static final String CLASS = "CLASS";

    private Class jsonClassType;

    @Override
    public Class<Object> returnedClass() {
        return Object.class;
    }

    @Override
    public int[] sqlTypes() {
        return new int[]{Types.JAVA_OBJECT};
    }

    @Override
    public Object nullSafeGet(ResultSet rs,
                              String[] names,
                              SharedSessionContractImplementor session,
                              Object owner)
            throws HibernateException, SQLException {

        final String cellContent = rs.getString(names[0]);
        if (cellContent == null) {
            return null;
        }
        try {
            final ObjectMapper mapper = new ObjectMapper();
            return mapper.readValue(cellContent.getBytes("UTF-8"), jsonClassType);
        } catch (final Exception ex) {
            throw new RuntimeException("Failed to convert String to Invoice: " + ex.getMessage(), ex);
        }
    }

    @Override
    public void nullSafeSet(PreparedStatement ps,
                            Object value,
                            int idx,
                            SharedSessionContractImplementor session)
            throws HibernateException, SQLException {
        if (value == null) {
            ps.setNull(idx,
                       Types.OTHER);
            return;
        }
        try {
            final ObjectMapper mapper = new ObjectMapper();
            final StringWriter w = new StringWriter();
            mapper.writeValue(w,
                              value);
            w.flush();
            ps.setObject(idx,
                         w.toString(),
                         Types.OTHER);
        } catch (final Exception ex) {
            throw new RuntimeException("Failed to convert Invoice to String: " + ex.getMessage(),
                                       ex);
        }

    }

    @Override
    public void setParameterValues(Properties parameters) {
        final String clazz = (String) parameters.get(CLASS);
        if (null != clazz) {
            jsonClassType = classLoaderService.classForName(clazz);
        }
    }

    @SuppressWarnings("unchecked")
    @Override
    public Object deepCopy(Object value) throws HibernateException {

        if (!(value instanceof Collection)) {
            return value;
        }

        Collection<?> collection = (Collection) value;
        Collection collectionClone = CollectionFactory.newInstance(collection.getClass());

        collectionClone.addAll(collection.stream()
                                         .map(this::deepCopy)
                                         .collect(Collectors.toList()));

        return collectionClone;
    }

    static final class CollectionFactory {
        @SuppressWarnings("unchecked")
        static <E, T extends Collection<E>> T newInstance(Class<T> collectionClass) {
            if (List.class.isAssignableFrom(collectionClass)) {
                return (T) new ArrayList<E>();
            } else if (Set.class.isAssignableFrom(collectionClass)) {
                return (T) new HashSet<E>();
            } else {
                throw new IllegalArgumentException("Unsupported collection type : " + collectionClass);
            }
        }
    }

    @Override
    public boolean isMutable() {
        return true;
    }

    @Override
    public boolean equals(Object x,
                          Object y) throws HibernateException {
        if (x == y) {
            return true;
        }

        if ((x == null) || (y == null)) {
            return false;
        }

        return x.equals(y);
    }

    @Override
    public int hashCode(Object x) throws HibernateException {
        assert (x != null);
        return x.hashCode();
    }

    @Override
    public Object assemble(Serializable cached,
                           Object owner) throws HibernateException {
        return deepCopy(cached);
    }

    @Override
    public Serializable disassemble(Object value) throws HibernateException {
        Object deepCopy = deepCopy(value);

        if (!(deepCopy instanceof Serializable)) {
            throw new SerializationException(String.format("%s is not serializable class",
                                                           value),
                                             null);
        }

        return (Serializable) deepCopy;
    }

    @Override
    public Object replace(Object original,
                          Object target,
                          Object owner) throws HibernateException {
        return deepCopy(original);
    }
}

And it is used in entity like this

@TypeDef(name = "addressValType", typeClass = JSONBUserType.class, parameters = {@Parameter(name = JSONBUserType.CLASS, value = "com.address.response.AddressResponse")})
@Table(name = "addressValidation")
public class Address implements Serializable {
    private static final long serialVersionUID = -2370572023911224797L;
    @Id
    @Column(name = "employeeNumber")
    private Integer employeeNumber;

    @Column(name = "inputAddress", columnDefinition = "jsonb")
    @Type(type = "addressValType")
    private SapPostalAddressResponse inputAddress;
  }
drt
  • 735
  • 6
  • 16