How to call an Oracle function from Hibernate with a return parameter?

Hibernate Session provides a doWork() method that gives you direct access to java.sql.Connection. You can then create and use java.sql.CallableStatement to execute your function:

session.doWork(new Work() {
  public void execute(Connection connection) throws SQLException {
    CallableStatement call = connection.prepareCall("{ ? = call MYSCHEMA.MYFUNC(?,?) }");
    call.registerOutParameter( 1, Types.INTEGER ); // or whatever it is
    call.setLong(2, id);
    call.setLong(3, transId);
    call.execute();
    int result = call.getInt(1); // propagate this back to enclosing class
  }
});

Yes, you do need to use an out parameter. If you use the doWork() method, you'd do something like this:

session.doWork(new Work() {
   public void execute(Connection conn) {
      CallableStatement stmt = conn.prepareCall("? = call <some function name>(?)");
      stmt.registerOutParameter(1, OracleTypes.INTEGER);
      stmt.setInt(2, <some value>);
      stmt.execute();
      Integer outputValue = stmt.getInt(1);
      // And then you'd do something with this outputValue
   }
});

You have the following options:

  1. With a @NamedNativeQuery:

     @org.hibernate.annotations.NamedNativeQuery(
         name = "fn_my_func",
         query = "{ ? = call MYSCHEMA.MYFUNC(?, ?) }",
         callable = true,
         resultClass = Integer.class
     )
    
     Integer result = (Integer) entityManager.createNamedQuery("fn_my_func")
         .setParameter(1, 1)
         .setParameter(2, 1)
         .getSingleResult();    
    
  2. With JDBC API:

     Session session = entityManager.unwrap( Session.class );
    
     final AtomicReference<Integer> result = 
         new AtomicReference<>();
    
     session.doWork( connection -> {
         try (CallableStatement function = connection
                 .prepareCall(
                     "{ ? = call MYSCHEMA.MYFUNC(?, ?) }"
                 )
             ) {
             function.registerOutParameter( 1, Types.INTEGER );
             function.setInt( 2, 1 );
             function.setInt( 3, 1 );
             function.execute();
             result.set( function.getInt( 1 ) );
         }
     } );            
    
  3. With a native Oracle query:

     Integer result = (Integer) entityManager.createNativeQuery(
         "SELECT MYSCHEMA.MYFUNC(:postId, :transId) FROM DUAL")
         .setParameter("postId", 1)
         .setParameter("transId", 1)
         .getSingleResult();