рдЗрд╕ рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдХреЛ рд▓рд┐рдЦрдиреЗ рдХреЗ рд▓рд┐рдП рдореБрдЭреЗ рдХреНрдпрд╛ рдкреНрд░реЗрд░рд┐рдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рдФрд░ рдХреНрдпреЛрдВ рдореМрдЬреВрджрд╛ рд╕рдорд╛рдзрд╛рди рдЦрд░рд╛рдм рд╣реИрдВ:
рджреБрд░реНрднрд╛рдЧреНрдп рд╕реЗ, рд╣рд╛рдЗрдмрд░рдиреЗрдЯ рдЬреИрд╕реЗ рд░рд╛рдХреНрд╖рд╕ "рд╣реИрд╡реАрд╡реЗрдЯ" рд╣реИрдВ рдФрд░ рдбреЗрдЯрд╛рдмреЗрд╕ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЕрдкрдирд╛ рд╕реНрд╡рдпрдВ рдХрд╛ рдПрдкреАрдЖрдИ рд▓рдЧрд╛рддреЗ рд╣реИрдВред рдореБрдЭреЗ рдПрдХ рд╕рд╛рдзрд╛рд░рдг рдкреБрд╕реНрддрдХрд╛рд▓рдп рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдереА рдЬрд┐рд╕реЗ рдирд┐рдпрдорд┐рдд JDBC рдХреЛрдб рдХреЗ рд╕рд╛рде рдорд┐рд╢реНрд░рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХреЗ (рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ, рдореБрдЭреЗ JDBC рдХреЗ рд▓рд┐рдП рдХрд┐рд╕реА рдкреНрд░рдХрд╛рд░ рдХреЗ Dapper.NET рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдереА)ред
рдкреБрд╕реНрддрдХрд╛рд▓рдп рд▓рд┐рдЦрдиреЗ рдореЗрдВ рдЙрдкрдпреЛрдЧ рдХрд┐рдП рдЬрд╛рдиреЗ рд╡рд╛рд▓реЗ рдореВрд▓ рд╕рд┐рджреНрдзрд╛рдВрдд:
- рд╕рд╛рджрдЧреА рдФрд░ рдкрд░рдорд╛рдгреБ - рдкреБрд╕реНрддрдХрд╛рд▓рдп 1 рдЬрд╛рд╡рд╛-рдлрд╝рд╛рдЗрд▓ рд╣реИ, рдкрд░рд┐рдпреЛрдЬрдирд╛ рдореЗрдВ рдЬреЛрдбрд╝рдиреЗ рдХреЗ рд▓рд┐рдП рдмрд╕ рдЕрдкрдиреЗ рд╕реНрд░реЛрдд рдореЗрдВ рдПрдХ рдлрд╝рд╛рдЗрд▓ рдЬреЛрдбрд╝реЗрдВред
- рдЧреИрд░-рдШреБрд╕рдкреИрда - рдкреБрд╕реНрддрдХрд╛рд▓рдп рдЕрдкрдиреЗ рдПрдкреАрдЖрдИ рдХреЛ рд▓рд╛рдЧреВ рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ, рдирд┐рдпрдорд┐рдд JDBC рдХреЛрдб рдХреЗ рд╕рд╛рде "рдорд┐рд╢реНрд░рдг" рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рд╕рдВрднрд╡ рд╣реИ
- рд╕реНрд╡рддрдВрддреНрд░рддрд╛ - рдкреБрд╕реНрддрдХрд╛рд▓рдп рдЬрд╛рд╡рд╛ рдПрд╕рдИ 5 рдХреЗ рдЕрд▓рд╛рд╡рд╛ рдХреБрдЫ рднреА рдирд╣реАрдВ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИ
- рдПрдХреНрд╕реНрдЯреЗрдВрд╕рд┐рдмрд┐рд▓рд┐рдЯреА - рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдПрдХ рд╡рд┐рд╢рд┐рд╖реНрдЯ рдкрд░рд┐рдпреЛрдЬрдирд╛ рдХреЗ рд▓рд┐рдП рдЖрд╡рд╢реНрдпрдХ рдПрдХреНрд╕рдЯреЗрдВрд╢рди рдЬреЛрдбрд╝рдиреЗ рдХрд╛ рд╕рдорд░реНрдерди рдХрд░рддреА рд╣реИ
рдорд╛рдкрджрдВрдбреЛрдВ рдХреЗ рдПрдХ рднрд░реЗ рд╣реБрдП рд╕рдВрдЧреНрд░рд╣ рдХреЗ рд╕рд╛рде рд░реЗрдбреАрд╕реНрдЯреЗрдбрдореЗрдВрдЯ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рд╡рд┐рдзрд┐ рдХрд╛ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрдиред
рдореИрдВ рдЗрд╕ рддрд░рд╣ рдХрд╛ рдХреЛрдб рд▓рд┐рдЦрдирд╛ рдЪрд╛рд╣реВрдВрдЧрд╛:
PreparedStatement stmt = DB.prepareStatement(conn, "select id, login, email from users where (login={0} or email={0}) and pass={1}", "dimzon", "pass")
рдпрд╣рд╛рдВ рдкреИрд░рд╛рдореАрдЯрд░ рдорд╛рдиреЛрдВ рдХреЛ рдЕрд▓рдЧ-рдЕрд▓рдЧ рдкрд╛рд░рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ рдФрд░ рдЕрдиреБрд░реЛрдз рдирд┐рдХрд╛рдп рдореЗрдВ {PARAMETER_ INDEX} рдирд┐рд░реНрдорд╛рдг рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдЙрдиреНрд╣реЗрдВ рд╕рдВрджрд░реНрднрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдЗрд╕ рддрд░рд╣ рдХреЗ рдПрдХ рд░рд┐рдХреЙрд░реНрдб рд╕рдВрдХреНрд╖рд┐рдкреНрдд рдФрд░ рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рд╣реИ (рдФрд░ .NET рдкреНрд░реЛрдЧреНрд░рд╛рдорд░ рд╕реЗ рдкрд░рд┐рдЪрд┐рдд)ред
рдЗрд╕ рдкреНрд░рдХрд╛рд░, рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рд╡рд┐рдзрд┐ рдШреЛрд╖рдгрд╛ рд╣реИ:
public static PreparedStatement prepareStatement(Connection cn, CharSequence query, Object... args) throws SQLException
рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдореЗрдВ 2 рд╕рдорд╕реНрдпрд╛рдУрдВ рдХреЛ рд╣рд▓ рдХрд░рдирд╛ рд╢рд╛рдорд┐рд▓ рд╣реИ:
- {PARAMETER_ INDEX} рдирд┐рд░реНрдорд╛рдг рдХреА рдкреНрд░рд╡рд┐рд╖реНрдЯрд┐ рдХреЗ рд▓рд┐рдП рдЕрдиреБрд░реЛрдз рдирд┐рдХрд╛рдп рдХреА рдЬрдЧрд╣, "?" рдФрд░ рдореИрдкрд┐рдВрдЧ "рдЖрд░реНрдЧрдиреНрд╕ рдореЗрдВ рдЗрдВрдбреЗрдХреНрд╕ -> рд░реЗрдбреАрдПрдЯрдореЗрдВрдЯ рдореЗрдВ рд╕реВрдЪрдХрд╛рдВрдХреЛрдВ рдХреА рд╕рд░рдгреА"
- рдЙрдкрдпреБрдХреНрдд рд╕реЗрдЯрдПрдХреНрд╕рдПрдХреНрд╕рдПрдХреНрд╕рдПрдХреНрд╕рдПрдХреНрд╕ рддрд░реАрдХреЛрдВ рдХреЛ рдХреЙрд▓ рдХрд░рдХреЗ рд░реЗрдбреАрд╕реНрдЯреЗрдбрдореЗрдВрдЯ рдореЗрдВ рдорд╛рдкрджрдВрдбреЛрдВ рдХрд╛ рдкреНрд░рддрд┐рд╕реНрдерд╛рдкрди
рдирд┐рдпрдорд┐рдд рдЕрднрд┐рд╡реНрдпрдХреНрддрд┐ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдкрд╣рд▓реА рд╕рдорд╕реНрдпрд╛ рд╣рд▓ рдХреА рдЬрд╛рддреА рд╣реИред рдФрд░ рджреВрд╕рд░реА рд╕рдорд╕реНрдпрд╛ рдХреЛ рд╣рд▓ рдХрд░рддреЗ рд╕рдордп, рдмрд╛рд░реАрдХрд┐рдпрд╛рдВ рдЙрддреНрдкрдиреНрди рд╣реЛрддреА рд╣реИрдВ:
- рдПрд╕рдХреНрдпреВрдПрд▓ рдкреИрд░рд╛рдореАрдЯрд░ рдХреЗ рдкреНрд░рдХрд╛рд░ рдХрд╛ рдирд┐рд░реНрдзрд╛рд░рдгред рд╕рд░рд▓ рдорд╛рдорд▓реЛрдВ (рдкреВрд░реНрдгрд╛рдВрдХ, рддрд┐рдерд┐) рдХреЗ рд▓рд┐рдП, рд╕рдм рдХреБрдЫ рд╕рд░рд▓ рд╣реИ, рд▓реЗрдХрд┐рди рдпрд╣ рд╕реНрдкрд╖реНрдЯ рдирд╣реАрдВ рд╣реИ рдХрд┐ рдЕрдЧрд░ рдХреБрдЫ рдЧреИрд░-рдорд╛рдирдХ рд╡рд░реНрдЧ рдПрдХ рддрд░реНрдХ рдХреЗ рд░реВрдк рдореЗрдВ рдкрд╛рд░рд┐рдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛ рддреЛ рдХреНрдпрд╛ рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдПред
- рдЕрд╢рдХреНрдд рдореВрд▓реНрдпреЛрдВ рдХреА рд╡реНрдпрд╛рдЦреНрдпрд╛ред Java рдореЗрдВ, null unyped рд╣реИ (рдЕрд░реНрдерд╛рдд рдЖрдк null.getClass () рдирд╣реАрдВ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ) - рдпрд╣ рд╕реНрдкрд╖реНрдЯ рдирд╣реАрдВ рд╣реИ рдХрд┐ рдХрд┐рд╕ java.sql.Types рдХреЛ PassedStatement.setNull рдореЗрдВ рдкрд╛рд╕ рдХрд░рдирд╛ рд╣реИред
рджреЛрдиреЛрдВ рд╕рдорд╕реНрдпрд╛рдУрдВ рдХреЛ рд╣рд▓ рдХрд░рдиреЗ рдореЗрдВ, "рд░рдгрдиреАрддрд┐" рдкреИрдЯрд░реНрди рд╣рдорд╛рд░реА рдорджрдж рдХрд░реЗрдЧрд╛:
public interface Param { void set(PreparedStatement ps, int index) throws SQLException; }
рдЬреАрд╡рди рдЖрд╕рд╛рди рд╣реЛ рдЧрдпрд╛ рд╣реИ - рдпрджрд┐ рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдЗрдирдкреБрдЯ рдкрд░ рдкрд░рдо рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХрд╛ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рд╣реИ, рддреЛ рд╣рдо рдмрд╕ рд╕реЗрдЯ рд╡рд┐рдзрд┐ рдХреЛ рдХрд╣рддреЗ рд╣реИрдВред рдорд╛рдирдХ рдорд╛рдорд▓реЛрдВ (рдкреВрд░реНрдгрд╛рдВрдХ, рддрд┐рдерд┐), рдПрдХрд░реВрдкрддрд╛ рдХреЗ рд▓рд┐рдП, рд╣рдо рд░рдгрдиреАрддрд┐рдпреЛрдВ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рднреА рдкрд░рд┐рдЪрдп рджреЗрдВрдЧреЗред рдЗрд╕рд▓рд┐рдП рд╣рдореЗрдВ рдкреИрд░рд╛рдореАрдЯрд░ рдХреЗ рдкреНрд░рдХрд╛рд░ (рдпрджрд┐ рдпрд╣ рд╢реБрд░реВ рдореЗрдВ рд░рдгрдиреАрддрд┐ рдирд╣реАрдВ рд╣реИ) рдХреЗ рдЖрдзрд╛рд░ рдкрд░ рд╕рд╣реА рд░рдгрдиреАрддрд┐ рдмрдирд╛рдиреЗ рдХреА рдПрдХ рд╡рд┐рдзрд┐ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред
рдпрд╣рд╛рдБ "рдлрд╝реИрдХреНрдЯрд░реА" рдкреИрдЯрд░реНрди рд╣рдорд╛рд░реА рдорджрдж рдХрд░реЗрдЧрд╛ред рд▓реЗрдХрд┐рди рдореИрдВрдиреЗ рдХрд╛рд░рдЦрд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдЕрд▓рдЧ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рд╢реБрд░реВ рдирд╣реАрдВ рдХрд┐рдпрд╛ рд╣реИ, рдореИрдВрдиреЗ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рд╕рд╛рд░ рд╡рд░реНрдЧ рд▓рд┐рдЦрд╛ рд╣реИ (.NET рдкреНрд░реЛрдЧреНрд░рд╛рдорд░ Func <T, R>) рдХреЗ рд╕рд╛рде рдПрдХ рдПрдирд╛рд▓реЙрдЧ рджреЗрдЦреЗрдВрдЧреЗред
public static abstract class FN<I,O> { public abstract O apply(I input) throws Exception; }
рдЗрд╕ рдкреНрд░рдХрд╛рд░, рдХрд╛рд░рдЦрд╛рдирд╛ рд╡рд░реНрдЧ рдПрдлрдПрди <рдСрдмреНрдЬреЗрдХреНрдЯ, рдкрд░рдо> рдХрд╛ рдПрдХ рд╡рдВрд╢рдЬ рд╣реИред
рдЬрд▓реНрджреА рд╕реЗ рдПрдХ рдХрд╛рд░рдЦрд╛рдиреЗ рдХрд╛ рдЙрджрд╛рд╣рд░рдг рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╕рдорд╡рд░реНрддреА рд╣рд╛рд╢рдкрд╛ <рдХреНрд▓рд╛рд╕, рдПрдлрдПрди <рдСрдмреНрдЬреЗрдХреНрдЯ, рдкрд░рдо >> рдкреИрд░рд╛рдореИрдкреНрдЯрд░реАрдЬ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВред
рдпрджрд┐ рд╣рдо рдЕрдкрдиреЗ рдХрд╛рд░рдЦрд╛рдиреЗ рдХреЛ рдЗрд╕ рдорд╛рдирдЪрд┐рддреНрд░ рдореЗрдВ рдЬреЛрдбрд╝рддреЗ рд╣реИрдВ, рддреЛ рд╣рдо рдЕрдкрдиреА рдХрдХреНрд╖рд╛ рдЙрддреНрддреАрд░реНрдг рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдЬреИрд╕рд╛ рдХрд┐ рддреИрдпрд╛рд░реА рдХреЗ рд▓рд┐рдП рд╣реИ - 1 рдФрд░ рд╡рд┐рдзрд┐ рджрд┐рдЦрд╛рдИ рджреЗрддреА рд╣реИ:
public static <E> void registerParamFactory(Class<E> forClass, FN<E, Param> factory)
рддрджрдиреБрд╕рд╛рд░, рдПрдХ рдЧреИрд░-рдорд╛рдирдХ рд╕реНрдерд┐рддрд┐ (рдПрдХреНрд╕реНрдЯреЗрдВрд╕рд┐рдмрд┐рд▓рд┐рдЯреА) рдХреЗ рд▓рд┐рдП, рджреЛ рджреГрд╖реНрдЯрд┐рдХреЛрдгреЛрдВ рдореЗрдВ рд╕реЗ рдПрдХ рдХреЛ рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ:
- рд╕реНрдкрд╖реНрдЯ рд░реВрдк рд╕реЗ рддреИрдпрд╛рд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдкрд░рдо рдХреЗ рдЕрдкрдиреЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХреЛ рдкрд╛рд╕ рдХрд░реЗрдВ
- рд░рдЬрд┐рд╕реНрдЯрд░рдкреНрд░реЗрдордлреИрдХреНрдЯреНрд░реА рдХреЗ рд╕рд╛рде рдкрд░рдо рдирд┐рд░реНрдорд╛рдг рдХрд╛рд░рдЦрд╛рдирд╛ рдкрдВрдЬреАрдХреГрдд рдХрд░реЗрдВ
рдЖрдЦрд┐рд░реА рд╕рд╡рд╛рд▓ рдпрд╣ рд╣реИ рдХрд┐ рдХреНрдпрд╛ рдХрд░рдирд╛ рд╣реИ рдЕрдЧрд░ рддреИрдпрд╛рд░реА рд╕реНрдЯрд╛рд▓рдореЗрдВрдЯ рд╢реВрдиреНрдп рдХреЗ рд╕рд╛рде рдЖрдПред рдкреНрд░рдХрд╛рд░ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдЕрдЧрд░ рдЗрд╕рдХреЗ рдмрдЬрд╛рдп "?" рд╕реАрдзреЗ рдЕрдиреБрд░реЛрдз рдирд┐рдХрд╛рдп рдореЗрдВ "NULL" рдбрд╛рд▓реЗрдВ, рдлрд┐рд░ рд╕рд░реНрд╡рд░ рдЗрд╕рдХрд╛ рдкрддрд╛ рд▓рдЧрд╛рдПрдЧрд╛ред
рдЗрд╕ рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП рдкреВрд░реНрдг рдХреЛрдб:
package a.poor.mans.orm.part1; import javax.xml.bind.JAXB; import java.io.IOException; import java.io.StringWriter; import java.sql.*; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.regex.Matcher; import java.util.regex.Pattern; public class DB { public interface Param { void set(PreparedStatement preparedStatement, int index) throws SQLException; } public static abstract class FN<I, O> { public abstract O apply(I input) throws Exception; public static <I, O> FN<I, O> constant(final O constValue) { return new FN<I, O>() { public O apply(I input) throws Exception { return constValue; } }; } } public static Param paramDate(final Date value) { return new Param() { public void set(PreparedStatement preparedStatement, int index) throws SQLException { if (value != null) preparedStatement.setDate(index, value); else preparedStatement.setNull(index, Types.DATE); } }; } public static Param paramTime(final Time value) { return new Param() { public void set(PreparedStatement preparedStatement, int index) throws SQLException { if (value != null) preparedStatement.setTime(index, value); else preparedStatement.setNull(index, Types.TIME); } }; } public static Param paramTimestamp(final Timestamp value) { return new Param() { public void set(PreparedStatement preparedStatement, int index) throws SQLException { if (value != null) preparedStatement.setTimestamp(index, value); else preparedStatement.setNull(index, Types.TIMESTAMP); } }; } public static Param paramString(final String value) { return new Param() { public void set(PreparedStatement preparedStatement, int index) throws SQLException { preparedStatement.setString(index, value); } }; } public static Param paramInteger(final Integer value) { return new Param() { public void set(PreparedStatement preparedStatement, int index) throws SQLException { if (value != null) preparedStatement.setInt(index, value); else preparedStatement.setNull(index, Types.INTEGER); } }; } public static Param paramLong(final Long value) { return new Param() { public void set(PreparedStatement preparedStatement, int index) throws SQLException { if (value != null) preparedStatement.setLong(index, value); else preparedStatement.setNull(index, Types.BIGINT); } }; } public static Param paramShort(final Short value) { return new Param() { public void set(PreparedStatement preparedStatement, int index) throws SQLException { if (value != null) preparedStatement.setShort(index, value); else preparedStatement.setNull(index, Types.SMALLINT); } }; } public static Param paramByte(final Byte value) { return new Param() { public void set(PreparedStatement preparedStatement, int index) throws SQLException { if (value != null) preparedStatement.setByte(index, value); else preparedStatement.setNull(index, Types.TINYINT); } }; } public static Param paramXML(final String value) { return new Param() { SQLXML sqlxml = null; public void set(PreparedStatement preparedStatement, int index) throws SQLException { if (value != null) { if (sqlxml == null) { sqlxml = preparedStatement.getConnection().createSQLXML(); sqlxml.setString(value); } preparedStatement.setSQLXML(index, sqlxml); } else { preparedStatement.setNull(index, Types.SQLXML); } } }; } public static Param paramXML(final SQLXML value) { return new Param() { public void set(PreparedStatement preparedStatement, int index) throws SQLException { if (value == null) preparedStatement.setNull(index, Types.SQLXML); else preparedStatement.setSQLXML(index, value); } }; } private final static Pattern INDEX_PATTERN = Pattern.compile("((?<!\\{)\\{)(\\d+)(\\}(?!\\}))"); private final static Pattern ESCAPE_OPEN = Pattern.compile("\\{\\{"); private final static Pattern ESCAPE_CLOSE = Pattern.compile("}}", Pattern.LITERAL); private static String object2xml(Object obj) { StringWriter stringWriter = new StringWriter(); try { try { JAXB.marshal(obj, stringWriter); } finally { stringWriter.close(); } return stringWriter.toString(); } catch (IOException e) { throw new RuntimeException(e.toString(), e); } } private final static Map<Class, FN> paramFactories = new ConcurrentHashMap<Class, FN>() { { put(SQLXML.class, new FN<SQLXML, Param>() { public Param apply(SQLXML input) throws Exception { return paramXML(input); } }); put(Collection.class, new FN<Collection, Param>() { public Param apply(Collection input) throws Exception { return paramXML(object2xml(input.toArray())); } }); put(String.class, new FN<String, Param>() { public Param apply(String input) throws Exception { return paramString(input); } }); put(java.sql.Date.class, new FN<java.sql.Date, Param>() { public Param apply(java.sql.Date input) throws Exception { return paramDate(input); } }); put(Time.class, new FN<Time, Param>() { public Param apply(Time input) throws Exception { return paramTime(input); } }); put(Timestamp.class, new FN<Timestamp, Param>() { public Param apply(Timestamp input) throws Exception { return paramTimestamp(input); } }); put(Boolean.class, emptyFN); put(Long.class, emptyFN); put(Integer.class, emptyFN); put(Short.class, emptyFN); put(byte.class, emptyFN); } }; public static <E> void registerParamFactory(Class<E> forClass, FN<E, Param> factory) { paramFactories.put(forClass, factory); for (Map.Entry<Class, FN> pair : paramFactories.entrySet()) { if (pair.getValue() == emptyFN) pair.setValue(null); } } private static FN getParamFactory(Class paramClass) { FN v = getParamFactory(paramClass, paramClass); if (v != null) return v; paramFactories.put(paramClass, emptyFN); return emptyFN; } private static FN getParamFactory(Class paramClass, Class targetClass) { FN val; for (Class current = paramClass; current != Object.class && current != null; current = current.getSuperclass()) { val = paramFactories.get(current); if (val != null) { if (current != targetClass) paramFactories.put(targetClass, val); return val; } for (Class intf : current.getInterfaces()) { val = getParamFactory(intf, targetClass); if (val != null) return val; } } return null; } private static final FN emptyFN = new FN() { public Object apply(Object input) throws Exception { return null; } }; @SuppressWarnings("unchecked") public static PreparedStatement prepareStatement(final Connection connection, final CharSequence query, final Object... args) throws SQLException { int argc = args.length; String[] strings = new String[argc]; Param[] params = new Param[argc]; Object[] indexes = new Object[argc]; for (int i = 0; i < argc; ++i) { Object arg = args[i]; if (null == arg) { strings[i] = "NULL"; } else if (arg instanceof Param) { params[i] = (Param) arg; } else { Class paramClass = arg.getClass(); FN factory = getParamFactory(paramClass); if (factory != null && factory != emptyFN) { try { params[i] = (Param) factory.apply(arg); } catch (Exception e) { throw new RuntimeException(e); } } else { if (arg instanceof Boolean) { strings[i] = ((Boolean) arg) ? "1" : "0"; } else if (arg instanceof Integer) { strings[i] = Integer.toString((Integer) arg); } else if (arg instanceof Long) { strings[i] = Long.toString((Long) arg); } else if (arg instanceof Short) { strings[i] = Short.toString((Short) arg); } else if (arg instanceof Byte) { strings[i] = Byte.toString((Byte) arg); } else { params[i] = paramXML(object2xml(arg)); } } } } Matcher matcher = INDEX_PATTERN.matcher(query); StringBuffer stringBuffer = new StringBuffer(); int index = 0; while (matcher.find()) { ++index; int reference = Integer.parseInt(matcher.group(2)); if (strings[reference] != null) { matcher.appendReplacement(stringBuffer, strings[reference]); } else { List<Integer> lst = (List<Integer>) (null == indexes[reference] ? (indexes[reference] = new ArrayList<Integer>()) : indexes[reference]); lst.add(index); matcher.appendReplacement(stringBuffer, "?"); } } matcher.appendTail(stringBuffer); String sql = ESCAPE_CLOSE.matcher(ESCAPE_OPEN.matcher(stringBuffer).replaceAll("{")).replaceAll("}"); PreparedStatement preparedStatement = connection.prepareStatement(sql); for (int i = 0; i < argc; ++i) { List<Integer> lst = (List<Integer>) indexes[i]; if (lst == null) continue; Param param = params[i]; for (Integer pos : lst) param.set(preparedStatement, pos); } return preparedStatement; } public static ResultSet executeQuery(final Connection connection, final CharSequence query, final Object... args) throws SQLException { PreparedStatement preparedStatement = prepareStatement(connection, query, args); try { return preparedStatement.executeQuery(); } finally { preparedStatement.close(); } } public static boolean execute(final Connection connection, final CharSequence query, final Object... args) throws SQLException { PreparedStatement preparedStatement = prepareStatement(connection, query, args); try { return preparedStatement.execute(); } finally { preparedStatement.close(); } } public static int executeUpdate(final Connection connection, final CharSequence query, final Object... args) throws SQLException { PreparedStatement preparedStatement = prepareStatement(connection, query, args); try { return preparedStatement.executeUpdate(); } finally { preparedStatement.close(); } } }