10

I want to know what exactly sql query is processed by jdbi sql api for debugging purposes. My interface class is following

public inteface myinteface{
    @SqlQuery("select :c1 from tablename where cond = :cd")
    String returnMeValue(@Bind("c1") String c1, @Bind("cd") Integer cd);
}

and later called in another class as String result = myinterfaceclassobject.returnMeValue("Name",1);

I am not getting expected answer so I want to see what actually going to the sql query. So is there any method to get the final processed query?

1
  • having the same question. Did you find out how to do it? Commented Jul 24, 2014 at 12:56

3 Answers 3

14

You can log the sql by writing SqlCustomizer.

import org.skife.jdbi.v2.StatementContext;
import org.skife.jdbi.v2.sqlobject.SqlStatementCustomizer;
import org.skife.jdbi.v2.sqlobject.SqlStatementCustomizerFactory;
import org.skife.jdbi.v2.sqlobject.SqlStatementCustomizingAnnotation;
import org.skife.jdbi.v2.tweak.StatementCustomizer;

import java.lang.annotation.*;
import java.lang.reflect.Method;
import java.sql.PreparedStatement;
import java.sql.SQLException;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@SqlStatementCustomizingAnnotation(LogSqlFactory.Factory.class)
public @interface LogSqlFactory {

    static class Factory implements SqlStatementCustomizerFactory {

        @Override
        public SqlStatementCustomizer createForMethod(Annotation annotation, Class sqlObjectType, Method method) {
            return null;
        }

        @Override
        public SqlStatementCustomizer createForType(Annotation annotation, Class sqlObjectType) {
            return q -> q.addStatementCustomizer(new StatementCustomizer() {
                @Override
                public void beforeExecution(PreparedStatement stmt, StatementContext ctx) throws SQLException {
                    System.out.println(stmt.toString());
                }

                @Override
                public void afterExecution(PreparedStatement stmt, StatementContext ctx) throws SQLException { }

                @Override
                public void cleanup(StatementContext ctx) throws SQLException { }
            });
        }

        @Override
        public SqlStatementCustomizer createForParameter(Annotation annotation, Class sqlObjectType, Method method, Object arg) {
            return null;
        }
    }

}

Just include this annotation and use this in SqlObject. In your case use this annotation like this,

@LogSqlFactory 
public inteface myinteface{
@SqlQuery("select :c1 from tablename where cond = :cd")
    String returnMeValue(@Bind("c1") String c1, @Bind("cd") Integer cd);
}

If you use custom loggers for logging, then beforeExecution method.

Sign up to request clarification or add additional context in comments.

2 Comments

I tried this but did not work. Is there any prerequisite?
@Manikandan I found your answer not working with newer versions of Jdbi and adjusted your solution here: stackoverflow.com/a/58763295/2986905 Feel free to integrate my rework into your answer and I will delete mine.
3

Based on @Manikandan's answer, which I found not working with Jdbi >= 3.10, I've adjusted the LogSqlFactory like this:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@SqlStatementCustomizingAnnotation(LogSqlFactory.Factory.class)
public @interface LogSqlFactory {

  class Factory implements SqlStatementCustomizerFactory {
    @Override
    public SqlStatementCustomizer createForType(Annotation annotation, Class sqlObjectType) {
      SqlLogger sqlLogger = new SqlLogger() {
        @Override
        public void logBeforeExecution(StatementContext context) {
          logSql(context);
        }
      };
      return statement -> statement.setSqlLogger(sqlLogger);
    }

    private static void logSql(StatementContext context) {
      System.out.println("Raw SQL:\n" + context.getRawSql());
      System.out.println("Parsed SQL:\n" + context.getParsedSql().getSql());
      System.out.println("Rendered SQL:\n" + context.getRenderedSql());
    }
  }
}

Annotate your SqlObject interface with the LogSqlFactory to see the SQL statements:

@LogSqlFactory 
public interface Dao {
  @SqlQuery("select * from t")
  List<?> selectAll();
}

Comments

0

It's much easier to use something like log4jdbc, using Manikandan's method also slows down your code quite a bit.

However if you would still like to use it and your project language level doesn't support lambdas, you can use the following modification:

  @Override
  public SqlStatementCustomizer createForType(Annotation annotation, final Class sqlObjectType) {

     return new SqlStatementCustomizer() {
        @Override
        public void apply(SQLStatement sqlStatement) throws SQLException {
           sqlStatement.addStatementCustomizer(new StatementCustomizer() {
              @Override
              public void beforeExecution(PreparedStatement stmt, StatementContext ctx) throws SQLException {
                 System.out.println(stmt.toString());
              }

              @Override
              public void afterExecution(PreparedStatement stmt, StatementContext ctx) throws SQLException {
              }

              @Override
              public void cleanup(StatementContext ctx) throws SQLException {
              }
           });
        }
     };

  }

However stmt.toString() is not guaranteed to return the SQL statement, it depends on the implementation. This will not work for SQLite.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.