Domanda

Here is my problem. Our company has decided to move from a proprietary data access system to using spring data access. Most of our code changes is simply changing how we call stored procs. For example.

Input:

public DataSet myMethodName1(Integer inputint1) {
    DAOInfo info = _newDAOInfo();
    info.setProperty(PROP_PROCNAME, "sp_name");
    info.addParameter("sp_param1", PARAMETER_TYPE_INPUT, DATATYPE_INT, inputint1);
    return _executeDAO(info);
}
public DataSet myMethodName2(String inputchar1, String inputchar2) {
    DAOInfo info = _newDAOInfo();
    info.setProperty(PROP_PROCNAME, "sp_name");
    info.addParameter("sp_param1", PARAMETER_TYPE_INPUT, DATATYPE_CHAR, inputchar1);
    info.addParameter("sp_param2", PARAMETER_TYPE_INPUT, DATATYPE_CHAR, inputchar2);
    return _executeDAO(info);
}

Output:

    public DataSet myMethodName1(Integer inputint1) {
        SimpleJdbcCall jdbcCall = new SimpleJdbcCall (dataSource).withProcedureName("sp_name");
        jdbcCall.setReturnValueRequired(true);
        jdbcCall.declareParameters(new SqlParameter("sp_param1", Types.INTEGER));
        jdbcCall.declareParameters(new SqlReturnResultSet(DATASET_PARAMETER_NAME, new DataSetResultSetExtractor()));

        Map<String, Object> in = new HashMap<String, Object>();
        in.put("sp_param1", profileId);
        return executeSP(jdbcCall, inputint1);
    }

    public DataSet myMethodName2(String inputchar1, String inputchar2) {
        SimpleJdbcCall jdbcCall = new SimpleJdbcCall (dataSource).withProcedureName("sp_name");
        jdbcCall.setReturnValueRequired(true);
        jdbcCall.declareParameters(new SqlParameter("sp_param1", Types.CHAR));
        jdbcCall.declareParameters(new SqlParameter("sp_param2", Types.CHAR));
        jdbcCall.declareParameters(new SqlReturnResultSet(DATASET_PARAMETER_NAME, new DataSetResultSetExtractor()));

        Map<String, Object> in = new HashMap<String, Object>();
        in.put("sp_param1", inputchar1);
        in.put("sp_param2", inputchar2);
        return executeSP(jdbcCall, in);
    }

I am not asking for anyone to solve the problem. I am simply looking for suggestion of tool or tools that would help me solve such a problem. Realize that the number of parameters in any one method could vary between 0 and 30.

The above example has 2 methods. I have a file with 100 methods methods just like these two methods. There are other smaller files that have this need. So it is worth a few hours of my time. This is the type of thing a computer is going to do better and more consistently then me manually doing a bunch of repetitive cut-paste.

It looks like with some time I could make a TextPad macros to do the job. But since TextPad macros are not editable, it is quite annoying. The tools I have available to me are Windows7, RAD, TextPad, Java or any other free tool that is out there. It feels like if there is a free editor that allows you to edit macros this could be quite easy.

UPDATE: I forgot to mention this code is in jar and needs to be backward-compatible, so I don't need solutions on how to fix my code.

Thanks for you thoughts or ideas.

È stato utile?

Soluzione 2

The change is far from being trivial - coding the proper parser or regex or macro or... will probably take more time than going through the code and making the changes manually.

In particular, if there are some comments, a regex won't work easily and you will need to actually parse the code...

However a regex could probably handle 70% of what you need and you can do the rest manually.

For example:

DAOInfo info = _newDAOInfo();
info.setProperty(PROP_PROCNAME, "sp_name");

becomes:

SimpleJdbcCall jdbcCall = new SimpleJdbcCall (dataSource).withProcedureName("sp_name");
jdbcCall.setReturnValueRequired(true);

In Netbeans, you can use the following regex ((?s) allows multiline matching - you can manually insert line breaks with \n or use the same indentation as in my example below):

  • find:

    (?s)DAOInfo\s+(.*?)\s*=\s*_newDAOInfo\(\);(\s+)(.*?)\.setProperty\(PROP_PROCNAME\, \"(.*?)\"\);
    
  • replace:

    SimpleJdbcCall jdbcCall = new SimpleJdbcCall (dataSource).withProcedureName("$4");$2jdbcCall.setReturnValueRequired(true);
    

You may need to clean the formatting aftwerwards.

Altri suggerimenti

My first attempt would be to wrap SimpleJdbcCall inside of DAOInfo in order to keep the API exactly the same and internally use the new features.

If you want to migrate to Spring, then I'd suggest to consider using POJOs instead of 30-argument methods and plus JPA annotations to map those to SQL. JPA 2.1 includes support for stored procedures.

Using POJOs has many advantages. Old code:

 foo.method("hello","what","is","this",....);

New code:

 UpdateFoo foo = new UpdateFoo();
 foo.setName("hello");
 foo.setQuestion("what");
 foo.setVerb("is");
 foo.setTarget("this");
 foo.execute();

-> You will stop mixing arguments.

Now some of that process can be automated. You can use the standalone Eclipse Java compiler to parse Java code. This gives you the Abstract Syntax Tree (AST) - an in-memory model of the Java code that you can analyze and convert. Refactorings use this to convert one form of code into another.

This approach is powerful but it takes some time to get used to working with an AST.

Another approach would be to use regular expressions. You will have faster success with them but they are only so powerful to parse recursive code. If you use regular expressions, then I suggest to write the converter in Java:

  1. You have a powerful IDE to edit and debug them
  2. You already know Java (you don't have to learn the editor's macro language)
  3. You can use various frameworks to make your life more simple

If you want a really powerful solution, have a look at jOOQ. jOOQ 3.0 has support to call stored procedures and the code generator will build most of the code for you.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top