Andy Andy - 6 months ago 253
Java Question

Spring: Generic RowMapper for dynamic queries

I am using SpringBatch to read from Oracle and write into ElasticSearch.

My code works fine for static query.
Example:

select emp_id, emp_name from employee_table
I have a RowMapper class that maps the values from resultSet with the Employee POJO.

My requirement is

The query will be inputted by the user. So the query might be as follows


  1. select emp_id, emp_name from employee_table

  2. select cust_id, cust_name, cust_age from customer_table

  3. select door_no, street_name, loc_name, city from address_table

  4. Similar queries



My questions are


  1. Id there a way to dynamically create a POJO according to the query given by the user?

  2. Will the RowMapper concept work if the query keeps changing as in my case?

  3. Is there something like a generic rowmapper?



Thanks for your time. Sample code would be much appreciated.

Answer

I found a solution to my problem by using Spring's ColumnMapRowMapper. Please find a snippet from the xml configuration file. I didn't generate any POJO class. I managed with a Map and inserted the same into ES. The map's key name should match with the field names present in index.

<step id="slave" xmlns="http://www.springframework.org/schema/batch">
    <tasklet>
        <chunk reader="pagingItemReader" writer="elasticSearcItemWriter"
            processor="itemProcessor" commit-interval="10" />
    </tasklet>
</step>



<bean id="pagingItemReader"
        class="org.springframework.batch.item.database.JdbcPagingItemReader"
        scope="step">
        <property name="dataSource" ref="dataSource" />
        <property name="queryProvider">
            <bean
                class="org.springframework.batch.item.database.support.SqlPagingQueryProviderFactoryBean">
                <property name="dataSource" ref="dataSource" />
                <property name="selectClause" value="*******" />
                <property name="fromClause" value="*******" />

                <property name="whereClause" value="*******" />
                <property name="sortKey" value="*******" />
            </bean>

        </property>
        <!-- Inject via the ExecutionContext in rangePartitioner -->
        <property name="parameterValues">
            <map>
                <entry key="fromId" value="#{stepExecutionContext[fromId]}" />
                <entry key="toId" value="#{stepExecutionContext[toId]}" />
            </map>
        </property>
        <property name="pageSize" value="10" />
        <property name="rowMapper">
            <bean class="org.springframework.jdbc.core.ColumnMapRowMapper" />
        </property>
    </bean>

And inside my elasticSearcItemWriter class....

public class ElasticSearchItemWriter<T> extends AbstractItemStreamItemWriter<T>
        implements ResourceAwareItemWriterItemStream<T>, InitializingBean {
....
....
....
@Override
    public void write(List<? extends T> items) throws Exception {


        client = jestClient.getJestClient();
        if (items.size() > 0) {
            for (Object item : items) {
                @SuppressWarnings("unchecked")
                Map<String, Object> map = (Map<String, Object>) item;
                // Asynch index
                Index index = new Index.Builder(map).index(Start.prop.getProperty(Constants.ES_INDEX_NAME))
                    .type(Start.prop.getProperty(Constants.ES_INDEX_TYPE)).build();


                client.executeAsync(index, new JestResultHandler<JestResult>() {
                    public void failed(Exception ex) {
                    }

                    public void completed(JestResult result) {
                    }
                });
            }
        }
    }
.....
....
}