1
votes

I need help on spring integration jdbc outbound gateway. I currently playing with the spring integration sample jdbc. I add codes to update data using jdbc outbound gateway, here is the spring-integration-context.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:int="http://www.springframework.org/schema/integration"
    xmlns:int-jdbc="http://www.springframework.org/schema/integration/jdbc"
    xmlns:jdbc="http://www.springframework.org/schema/jdbc"
    xsi:schemaLocation="http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
        http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
        http://www.springframework.org/schema/integration/jdbc http://www.springframework.org/schema/integration/jdbc/spring-integration-jdbc.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <jdbc:embedded-database id="datasource" type="H2">
        <jdbc:script location="classpath:setup-tables.sql"/>        
    </jdbc:embedded-database>

    <!-- See also:
        http://static.springsource.org/spring-integration/reference/htmlsingle/#gateway-proxy
        http://www.eaipatterns.com/MessagingGateway.html -->

    <int:channel id="createPersonRequestChannel"/>
    <int:channel id="createPersonReplyChannel"/>
    <int:channel id="findPersonRequestChannel"/>
    <int:channel id="findPersonReplyChannel"/>
    <int:channel id="updatePersonRequestChannel"/>
    <int:channel id="updatePersonReplyChannel"/>

    <int:gateway id="personService" service-interface="org.springframework.integration.samples.jdbc.service.PersonService">
        <int:method name="createPerson" 
                    request-channel="createPersonRequestChannel"
                    request-timeout="5000"
                    reply-channel="createPersonReplyChannel"
                    reply-timeout="5000"/>
        <int:method name="updatePerson" 
                    request-channel="updatePersonRequestChannel"
                    request-timeout="5000"
                    reply-channel="updatePersonReplyChannel"
                    reply-timeout="5000"/>
        <int:method name="findPersonByName"
                    request-channel="findPersonRequestChannel"
                    request-timeout="5000"
                    reply-channel="findPersonReplyChannel"
                    reply-timeout="5000"/>          
    </int:gateway>

    <int-jdbc:outbound-gateway data-source="datasource"
        update="UPDATE DUMMY SET DUMMY_VALUE='test'"
                               request-channel="findPersonRequestChannel" 
                               query="select * from Person where lower(name)=lower(:payload)"
                               reply-channel="findPersonReplyChannel" row-mapper="personResultMapper"
                               max-rows-per-poll="100">
    </int-jdbc:outbound-gateway>



    <bean id="personResultMapper" class="org.springframework.integration.samples.jdbc.PersonMapper"/>
    <int-jdbc:outbound-gateway data-source="datasource" 
                                request-channel="createPersonRequestChannel"
                                reply-channel="createPersonReplyChannel"
                                update="insert into Person (name,gender,dateOfBirth) 
                                        values
                                        (:name,:gender,:dateOfBirth)"
                                query="select * from Person where id = :id"     
                                request-sql-parameter-source-factory="requestSource"
                                reply-sql-parameter-source-factory="replySource"
                                row-mapper="personResultMapper"
                                keys-generated="true"/>

    <int-jdbc:outbound-gateway data-source="datasource" 
                                request-channel="updatePersonRequestChannel"
                                reply-channel="updatePersonReplyChannel"
                                update="update Person 
                                        set name = :name, gender = :gender  
                                        where id = :id"
                                query="select * from Person where id = :id" 
                                request-sql-parameter-source-factory="requestSource"
                                reply-sql-parameter-source-factory="replySource"
                                row-mapper="personResultMapper"/>

    <bean id="replySource" class="org.springframework.integration.jdbc.ExpressionEvaluatingSqlParameterSourceFactory">
        <property name="parameterExpressions">
            <map>
                <entry key="id" value="#this['SCOPE_IDENTITY()']"/>             
            </map>
        </property>
    </bean> 

    <bean id="requestSource" class="org.springframework.integration.jdbc.ExpressionEvaluatingSqlParameterSourceFactory">
        <property name="parameterExpressions">
            <map>
                <entry key="name" value="payload.name.toUpperCase()"/>
                <entry key="gender" value="payload.gender.identifier"/>
                <entry key="dateOfBirth" value="payload.dateOfBirth"/>
            </map>
        </property>
    </bean> 

</beans>

Here is my PersonService.java:

package org.springframework.integration.samples.jdbc.service;

import java.util.List;

import org.springframework.integration.samples.jdbc.Person;

/**
 * The Service used to create Person instance in database
 * @author Amol Nayak
 *
 */
public interface PersonService {

    /**
     * Creates a {@link Person} instance from the {@link Person} instance passed
     * 
     * @param the created person instance, it will contain the generated primary key and the formated name
     * @return
     */
    Person createPerson(Person person);

    /**
     * Find the person by the person name, the name search is case insensitive, however the 
     * spaces are not ignored
     *  
     * @param name
     * @return the matching {@link Person} record
     */
    List<Person> findPersonByName(String name);

    Person updatePerson(Person person);
}

The Main.java:

public final class Main {

    private static final Logger LOGGER = Logger.getLogger(Main.class);

    private Main() { }

    /**
     * Load the Spring Integration Application Context
     *
     * @param args - command line arguments
     */
    public static void main(final String... args) {

        LOGGER.info("\n========================================================="
                  + "\n                                                         "
                  + "\n          Welcome to Spring Integration!                 "
                  + "\n                                                         "
                  + "\n    For more information please visit:                   "
                  + "\n    http://www.springsource.org/spring-integration       "
                  + "\n                                                         "
                  + "\n=========================================================" );

        final AbstractApplicationContext context =
                new ClassPathXmlApplicationContext("classpath:META-INF/spring/integration/*-context.xml");

        context.registerShutdownHook();

        final Scanner scanner = new Scanner(System.in);


        final PersonService personService = context.getBean(PersonService.class);

        LOGGER.info("\n========================================================="
                  + "\n                                                         "
                  + "\n    Please press 'q + Enter' to quit the application.    "
                  + "\n                                                         "
                  + "\n=========================================================" );

        System.out.println("Please enter a choice and press <enter>: ");
        System.out.println("\t1. Find person details");
        System.out.println("\t2. Create a new person detail");
        System.out.println("\t3. Update a person detail");
        System.out.println("\tq. Quit the application");
        System.out.print("Enter you choice: ");
        while (true) {
            final String input = scanner.nextLine();
            if("1".equals(input.trim())) {
                getPersonDetails(scanner, personService);
            } else if("2".equals(input.trim())) {
                createPersonDetails(scanner,personService);
            } else if("3".equals(input.trim())) {
                updatePersonDetails(scanner,personService);
            } else if("q".equals(input.trim())) {
                break;
            } else {
                System.out.println("Invalid choice\n\n");
            }

            System.out.println("Please enter a choice and press <enter>: ");
            System.out.println("\t1. Find person details");
            System.out.println("\t2. Create a new person detail");
            System.out.println("\tq. Quit the application");
            System.out.print("Enter you choice: ");
        }

        LOGGER.info("Exiting application...bye.");

        System.exit(0);

    }

    private static void createPersonDetails(final Scanner scanner,PersonService service) {
        while(true) {
            System.out.print("\nEnter the Person's name:");
            String name = scanner.nextLine();
            Gender gender;
            while(true) {
                System.out.print("Enter the Person's gender(M/F):");
                String genderStr = scanner.nextLine();
                if("m".equalsIgnoreCase(genderStr) || "f".equalsIgnoreCase(genderStr)) {
                    gender = Gender.getGenderByIdentifier(genderStr.toUpperCase());
                    break;
                }
            }
            Date dateOfBirth;
            SimpleDateFormat format = new SimpleDateFormat("dd/MM/yyyy");
            while(true) {
                System.out.print("Enter the Person's Date of birth in DD/MM/YYYY format:");
                String dobStr = scanner.nextLine();
                try {
                    dateOfBirth = format.parse(dobStr);
                    break;
                } catch (ParseException e) {
                    //Silently suppress and ask to enter details again
                }
            }

            Person person = new Person();
            person.setDateOfBirth(dateOfBirth);
            person.setGender(gender);
            person.setName(name);
            person = service.createPerson(person);
            System.out.println("Created person record with id: " + person.getPersonId());
            System.out.print("Do you want to create another person? (y/n)");
            String choice  = scanner.nextLine();
            if(!"y".equalsIgnoreCase(choice))
                break;
        }
    }
    private static void updatePersonDetails(final Scanner scanner,PersonService service) {
        while(true) {
            System.out.print("\nEnter the new Person's name:");
            String name = scanner.nextLine();
            Gender gender;
            while(true) {
                System.out.print("Enter the new Person's gender(M/F):");
                String genderStr = scanner.nextLine();
                if("m".equalsIgnoreCase(genderStr) || "f".equalsIgnoreCase(genderStr)) {
                    gender = Gender.getGenderByIdentifier(genderStr.toUpperCase());
                    break;
                }
            }
            Integer id;
            while(true) {
                System.out.print("Enter the Person's id:");
                String idStr = scanner.nextLine();
                id = Integer.valueOf(idStr);
                break;
            }

            Person person = new Person();
            person.setName(name);
            person.setGender(gender);
            person.setPersonId(id);
            service.updatePerson(person);
            System.out.println("Updated person record with id: " + person.getPersonId());
            break;
        }
    }
    /**
     * @param service
     * @param input
     */
    private static void getPersonDetails(final Scanner scanner,final PersonService service) {
        while(true) {
            System.out.print("Please enter the name of the person and press<enter>: ");
            String input = scanner.nextLine();
            final List<Person> personList = service.findPersonByName(input);
            if(personList != null && !personList.isEmpty()) {
                for(Person person:personList) {
                    System.out.print(
                            String.format("Person found - Person Id: '%d', Person Name is: '%s',  Gender: '%s'",
                                          person.getPersonId(),person.getName(), person.getGender()));
                    System.out.println(String.format(", Date of birth: '%1$td/%1$tm/%1$tC%1$ty'", person.getDateOfBirth()));
                }
            } else {
                System.out.println(
                        String.format("No Person record found for name: '%s'.", input));
            }
            System.out.print("Do you want to find another person? (y/n)");
            String choice  = scanner.nextLine();
            if(!"y".equalsIgnoreCase(choice))
                break;
        }

    }
}

Why I always get this error message whenever I tried to run it?

04:36:29.402 WARN  [main][org.springframework.integration.gateway.GatewayProxyFactoryBean$MethodInvocationGateway] failure occurred in gateway sendAndReceive
org.springframework.integration.MessageHandlingException: error occurred in message handler [org.springframework.integration.jdbc.JdbcOutboundGateway#2]
    at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:79)
    at org.springframework.integration.dispatcher.UnicastingDispatcher.doDispatch(UnicastingDispatcher.java:115)
    at org.springframework.integration.dispatcher.UnicastingDispatcher.dispatch(UnicastingDispatcher.java:102)
    at org.springframework.integration.channel.AbstractSubscribableChannel.doSend(AbstractSubscribableChannel.java:77)
    at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:157)
    at org.springframework.integration.core.MessagingTemplate.doSend(MessagingTemplate.java:288)
    at org.springframework.integration.core.MessagingTemplate.doSendAndReceive(MessagingTemplate.java:318)
    at org.springframework.integration.core.MessagingTemplate.sendAndReceive(MessagingTemplate.java:239)
    at org.springframework.integration.core.MessagingTemplate.convertSendAndReceive(MessagingTemplate.java:274)
    at org.springframework.integration.gateway.MessagingGatewaySupport.doSendAndReceive(MessagingGatewaySupport.java:224)
    at org.springframework.integration.gateway.MessagingGatewaySupport.sendAndReceive(MessagingGatewaySupport.java:203)
    at org.springframework.integration.gateway.GatewayProxyFactoryBean.invokeGatewayMethod(GatewayProxyFactoryBean.java:306)
    at org.springframework.integration.gateway.GatewayProxyFactoryBean.doInvoke(GatewayProxyFactoryBean.java:269)
    at org.springframework.integration.gateway.GatewayProxyFactoryBean.invoke(GatewayProxyFactoryBean.java:260)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
    at com.sun.proxy.$Proxy0.updatePerson(Unknown Source)
    at org.springframework.integration.samples.jdbc.Main.updatePersonDetails(Main.java:172)
    at org.springframework.integration.samples.jdbc.Main.main(Main.java:89)
Caused by: org.springframework.jdbc.UncategorizedSQLException: PreparedStatementCallback; uncategorized SQLException for SQL [update Person            set name = ?, gender = ?             where id = ?]; SQL state [90026]; error code [90026]; Serialization failed, cause: "java.io.NotSerializableException: java.lang.Object" [90026-168]; nested exception is org.h2.jdbc.JdbcSQLException: Serialization failed, cause: "java.io.NotSerializableException: java.lang.Object" [90026-168]
    at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:83)
    at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:80)
    at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:80)
    at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:603)
    at org.springframework.jdbc.core.JdbcTemplate.update(JdbcTemplate.java:812)
    at org.springframework.jdbc.core.JdbcTemplate.update(JdbcTemplate.java:834)
    at org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate.update(NamedParameterJdbcTemplate.java:260)
    at org.springframework.integration.jdbc.JdbcMessageHandler.executeUpdateQuery(JdbcMessageHandler.java:124)
    at org.springframework.integration.jdbc.JdbcOutboundGateway.handleRequestMessage(JdbcOutboundGateway.java:128)
    at org.springframework.integration.handler.AbstractReplyProducingMessageHandler.handleMessageInternal(AbstractReplyProducingMessageHandler.java:134)
    at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:73)
    ... 18 more
Caused by: org.h2.jdbc.JdbcSQLException: Serialization failed, cause: "java.io.NotSerializableException: java.lang.Object" [90026-168]
    at org.h2.message.DbException.getJdbcSQLException(DbException.java:329)
    at org.h2.message.DbException.get(DbException.java:158)
    at org.h2.util.Utils.serialize(Utils.java:260)
    at org.h2.value.ValueJavaObject.getNoCopy(ValueJavaObject.java:42)
    at org.h2.value.DataType.convertToValue(DataType.java:941)
    at org.h2.jdbc.JdbcPreparedStatement.setObject(JdbcPreparedStatement.java:439)
    at org.springframework.jdbc.core.StatementCreatorUtils.setValue(StatementCreatorUtils.java:365)
    at org.springframework.jdbc.core.StatementCreatorUtils.setParameterValueInternal(StatementCreatorUtils.java:217)
    at org.springframework.jdbc.core.StatementCreatorUtils.setParameterValue(StatementCreatorUtils.java:128)
    at org.springframework.jdbc.core.PreparedStatementCreatorFactory$PreparedStatementCreatorImpl.setValues(PreparedStatementCreatorFactory.java:298)
    at org.springframework.jdbc.core.PreparedStatementCreatorFactory$PreparedStatementCreatorImpl.createPreparedStatement(PreparedStatementCreatorFactory.java:251)
    at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:581)
    ... 25 more
Caused by: java.io.NotSerializableException: java.lang.Object
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1183)
    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:347)
    at org.h2.util.Utils.serialize(Utils.java:257)
    ... 34 more
Exception in thread "main" org.springframework.jdbc.UncategorizedSQLException: PreparedStatementCallback; uncategorized SQLException for SQL [update Person            set name = ?, gender = ?             where id = ?]; SQL state [90026]; error code [90026]; Serialization failed, cause: "java.io.NotSerializableException: java.lang.Object" [90026-168]; nested exception is org.h2.jdbc.JdbcSQLException: Serialization failed, cause: "java.io.NotSerializableException: java.lang.Object" [90026-168]
    at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:83)
    at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:80)
    at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:80)
    at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:603)
    at org.springframework.jdbc.core.JdbcTemplate.update(JdbcTemplate.java:812)
    at org.springframework.jdbc.core.JdbcTemplate.update(JdbcTemplate.java:834)
    at org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate.update(NamedParameterJdbcTemplate.java:260)
    at org.springframework.integration.jdbc.JdbcMessageHandler.executeUpdateQuery(JdbcMessageHandler.java:124)
    at org.springframework.integration.jdbc.JdbcOutboundGateway.handleRequestMessage(JdbcOutboundGateway.java:128)
    at org.springframework.integration.handler.AbstractReplyProducingMessageHandler.handleMessageInternal(AbstractReplyProducingMessageHandler.java:134)
    at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:73)
    at org.springframework.integration.dispatcher.UnicastingDispatcher.doDispatch(UnicastingDispatcher.java:115)
    at org.springframework.integration.dispatcher.UnicastingDispatcher.dispatch(UnicastingDispatcher.java:102)
    at org.springframework.integration.channel.AbstractSubscribableChannel.doSend(AbstractSubscribableChannel.java:77)
    at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:157)
    at org.springframework.integration.core.MessagingTemplate.doSend(MessagingTemplate.java:288)
    at org.springframework.integration.core.MessagingTemplate.doSendAndReceive(MessagingTemplate.java:318)
    at org.springframework.integration.core.MessagingTemplate.sendAndReceive(MessagingTemplate.java:239)
    at org.springframework.integration.core.MessagingTemplate.convertSendAndReceive(MessagingTemplate.java:274)
    at org.springframework.integration.gateway.MessagingGatewaySupport.doSendAndReceive(MessagingGatewaySupport.java:224)
    at org.springframework.integration.gateway.MessagingGatewaySupport.sendAndReceive(MessagingGatewaySupport.java:203)
    at org.springframework.integration.gateway.GatewayProxyFactoryBean.invokeGatewayMethod(GatewayProxyFactoryBean.java:306)
    at org.springframework.integration.gateway.GatewayProxyFactoryBean.doInvoke(GatewayProxyFactoryBean.java:269)
    at org.springframework.integration.gateway.GatewayProxyFactoryBean.invoke(GatewayProxyFactoryBean.java:260)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
    at com.sun.proxy.$Proxy0.updatePerson(Unknown Source)
    at org.springframework.integration.samples.jdbc.Main.updatePersonDetails(Main.java:172)
    at org.springframework.integration.samples.jdbc.Main.main(Main.java:89)
Caused by: org.h2.jdbc.JdbcSQLException: Serialization failed, cause: "java.io.NotSerializableException: java.lang.Object" [90026-168]
    at org.h2.message.DbException.getJdbcSQLException(DbException.java:329)
    at org.h2.message.DbException.get(DbException.java:158)
    at org.h2.util.Utils.serialize(Utils.java:260)
    at org.h2.value.ValueJavaObject.getNoCopy(ValueJavaObject.java:42)
    at org.h2.value.DataType.convertToValue(DataType.java:941)
    at org.h2.jdbc.JdbcPreparedStatement.setObject(JdbcPreparedStatement.java:439)
    at org.springframework.jdbc.core.StatementCreatorUtils.setValue(StatementCreatorUtils.java:365)
    at org.springframework.jdbc.core.StatementCreatorUtils.setParameterValueInternal(StatementCreatorUtils.java:217)
    at org.springframework.jdbc.core.StatementCreatorUtils.setParameterValue(StatementCreatorUtils.java:128)
    at org.springframework.jdbc.core.PreparedStatementCreatorFactory$PreparedStatementCreatorImpl.setValues(PreparedStatementCreatorFactory.java:298)
    at org.springframework.jdbc.core.PreparedStatementCreatorFactory$PreparedStatementCreatorImpl.createPreparedStatement(PreparedStatementCreatorFactory.java:251)
    at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:581)
    ... 25 more
Caused by: java.io.NotSerializableException: java.lang.Object
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1183)
    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:347)
    at org.h2.util.Utils.serialize(Utils.java:257)
    ... 34 more

The Person.java POJO:

public class Person implements Serializable {

    private int personId;
    private String name;
    private Gender gender;
    private Date dateOfBirth;



    /**
     * Sets the person id
     * @return
     */
    public int getPersonId() {
        return personId;
    }
    /**
     * Get the person Id
     * @param personId
     */
    public void setPersonId(int personId) {
        this.personId = personId;
    }

    /**
     * Gets the name of the person
     * @return
     */
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }

    /**
     * Gets the gender of the person 
     * @return
     */
    public Gender getGender() {
        return gender;
    }
    public void setGender(Gender gender) {
        this.gender = gender;
    }

    /**
     * Gets the date of birth of the person
     * @return
     */
    public Date getDateOfBirth() {
        return dateOfBirth;
    }
    public void setDateOfBirth(Date dateOfBirth) {
        this.dateOfBirth = dateOfBirth;
    }   
}

Please help me, I don't know which java.lang.Object, since I don't use it anywhere in my code. Thanks

1
Does your Person class implements serializable? Every payload for ant message should implement serializable or should be handled by a message converter.Stefaan Neyts
@StefaanNeyts yes I have implements serializable, but still get the same error. Any other suggestions? Thanksthe.wizard
Is Gender an enum? I know that enums are serialized in a different way... But it should work. Maybe try to ommit the Gender to check it's not for that reason.Stefaan Neyts

1 Answers

2
votes

You have missed an id for the UPDATE:

<bean id="requestSource" class="org.springframework.integration.jdbc.ExpressionEvaluatingSqlParameterSourceFactory">
        <property name="parameterExpressions">
            <map>
                <entry key="id" value="payload.personId"/>
                <entry key="name" value="payload.name.toUpperCase()"/>
                <entry key="gender" value="payload.gender.identifier"/>
                <entry key="dateOfBirth" value="payload.dateOfBirth"/>
            </map>
        </property>
</bean> 

Plus there is need a separate ExpressionEvaluatingSqlParameterSourceFactory for the SELECT on that UPDATE :

<bean id="updateReplySource"
      class="org.springframework.integration.jdbc.ExpressionEvaluatingSqlParameterSourceFactory">
    <property name="parameterExpressions">
        <map>
            <entry key="id" value="payload.personId"/>
        </map>
    </property>
</bean>