CAMEL-6368: Added support for outputClass to map to a bean like sql component can do.
Project: http://git-wip-us.apache.org/repos/asf/camel/repo Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/edde4da8 Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/edde4da8 Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/edde4da8 Branch: refs/heads/camel-2.12.x Commit: edde4da817bcab6889f2a636f81e5bf591883af5 Parents: 6063702 Author: Claus Ibsen <davscl...@apache.org> Authored: Wed Sep 18 15:28:54 2013 +0200 Committer: Claus Ibsen <davscl...@apache.org> Committed: Wed Sep 18 15:29:08 2013 +0200 ---------------------------------------------------------------------- .../camel/component/jdbc/BeanRowMapper.java | 25 +++++++++ .../component/jdbc/DefaultBeanRowMapper.java | 54 ++++++++++++++++++++ .../camel/component/jdbc/JdbcEndpoint.java | 18 +++++++ .../camel/component/jdbc/JdbcProducer.java | 36 +++++++++++-- .../camel/component/jdbc/CustomerModel.java | 39 ++++++++++++++ ...ducerOutputTypeSelectOneOutputClassTest.java | 51 ++++++++++++++++++ .../JdbcProducerOutputTypeSelectOneTest.java | 53 +++++++++++++++++++ 7 files changed, 271 insertions(+), 5 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/camel/blob/edde4da8/components/camel-jdbc/src/main/java/org/apache/camel/component/jdbc/BeanRowMapper.java ---------------------------------------------------------------------- diff --git a/components/camel-jdbc/src/main/java/org/apache/camel/component/jdbc/BeanRowMapper.java b/components/camel-jdbc/src/main/java/org/apache/camel/component/jdbc/BeanRowMapper.java new file mode 100644 index 0000000..e500f5e --- /dev/null +++ b/components/camel-jdbc/src/main/java/org/apache/camel/component/jdbc/BeanRowMapper.java @@ -0,0 +1,25 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.jdbc; + +/** + * A mapper to map row names to java bean setter names, when using the <tt>outputClass</tt> option. + */ +public interface BeanRowMapper { + + String map(String row, Object value); +} http://git-wip-us.apache.org/repos/asf/camel/blob/edde4da8/components/camel-jdbc/src/main/java/org/apache/camel/component/jdbc/DefaultBeanRowMapper.java ---------------------------------------------------------------------- diff --git a/components/camel-jdbc/src/main/java/org/apache/camel/component/jdbc/DefaultBeanRowMapper.java b/components/camel-jdbc/src/main/java/org/apache/camel/component/jdbc/DefaultBeanRowMapper.java new file mode 100644 index 0000000..0416573 --- /dev/null +++ b/components/camel-jdbc/src/main/java/org/apache/camel/component/jdbc/DefaultBeanRowMapper.java @@ -0,0 +1,54 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.jdbc; + +/** + * The default {@link BeanRowMapper} will map row names to lower case names, + * but use a single upper case letter after underscores or dashes (which is skipped). + * <p/> + * For example <tt>CUST_ID</tt> is mapped as <tt>custId</tt>. + */ +public class DefaultBeanRowMapper implements BeanRowMapper { + + @Override + public String map(String row, Object value) { + // convert to lover case, and underscore as new upper case name; + return mapRowName(row); + } + + protected String mapRowName(String row) { + StringBuilder sb = new StringBuilder(); + boolean toUpper = false; + for (char ch : row.toCharArray()) { + if (ch == '_' || ch == '-') { + toUpper = true; + continue; + } + if (toUpper) { + char upper = Character.toLowerCase(ch); + sb.append(upper); + // reset flag + toUpper = false; + } else { + char lower = Character.toLowerCase(ch); + sb.append(lower); + } + } + return sb.toString(); + } + +} http://git-wip-us.apache.org/repos/asf/camel/blob/edde4da8/components/camel-jdbc/src/main/java/org/apache/camel/component/jdbc/JdbcEndpoint.java ---------------------------------------------------------------------- diff --git a/components/camel-jdbc/src/main/java/org/apache/camel/component/jdbc/JdbcEndpoint.java b/components/camel-jdbc/src/main/java/org/apache/camel/component/jdbc/JdbcEndpoint.java index 9751aa2..f743928 100755 --- a/components/camel-jdbc/src/main/java/org/apache/camel/component/jdbc/JdbcEndpoint.java +++ b/components/camel-jdbc/src/main/java/org/apache/camel/component/jdbc/JdbcEndpoint.java @@ -40,6 +40,8 @@ public class JdbcEndpoint extends DefaultEndpoint { private boolean allowNamedParameters = true; private boolean useHeadersAsParameters; private JdbcOutputType outputType = JdbcOutputType.SelectList; + private String outputClass; + private BeanRowMapper beanRowMapper = new DefaultBeanRowMapper(); public JdbcEndpoint() { } @@ -160,6 +162,22 @@ public class JdbcEndpoint extends DefaultEndpoint { this.outputType = outputType; } + public String getOutputClass() { + return outputClass; + } + + public void setOutputClass(String outputClass) { + this.outputClass = outputClass; + } + + public BeanRowMapper getBeanRowMapper() { + return beanRowMapper; + } + + public void setBeanRowMapper(BeanRowMapper beanRowMapper) { + this.beanRowMapper = beanRowMapper; + } + @Override protected String createEndpointUri() { return "jdbc"; http://git-wip-us.apache.org/repos/asf/camel/blob/edde4da8/components/camel-jdbc/src/main/java/org/apache/camel/component/jdbc/JdbcProducer.java ---------------------------------------------------------------------- diff --git a/components/camel-jdbc/src/main/java/org/apache/camel/component/jdbc/JdbcProducer.java b/components/camel-jdbc/src/main/java/org/apache/camel/component/jdbc/JdbcProducer.java index 6c35d83..d573587 100644 --- a/components/camel-jdbc/src/main/java/org/apache/camel/component/jdbc/JdbcProducer.java +++ b/components/camel-jdbc/src/main/java/org/apache/camel/component/jdbc/JdbcProducer.java @@ -331,12 +331,38 @@ public class JdbcProducer extends DefaultProducer { if (data.size() > 1) { throw new SQLDataException("Query result not unique for outputType=SelectOne. Got " + data.size() + " count instead."); } else if (data.size() == 1) { - // Set content depend on number of column from query result - Map<String, Object> row = data.get(0); - if (row.size() == 1) { - result = row.values().iterator().next(); + if (getEndpoint().getOutputClass() == null) { + // Set content depend on number of column from query result + Map<String, Object> row = data.get(0); + if (row.size() == 1) { + result = row.values().iterator().next(); + } else { + result = row; + } } else { - result = row; + Class<?> outputClzz = getEndpoint().getCamelContext().getClassResolver().resolveClass(getEndpoint().getOutputClass()); + Object answer = getEndpoint().getCamelContext().getInjector().newInstance(outputClzz); + + Map<String, Object> row = data.get(0); + Map<String, Object> properties = new LinkedHashMap<String, Object>(data.size()); + + // map row names using the bean row mapper + for (Map.Entry<String, Object> entry : row.entrySet()) { + Object value = entry.getValue(); + String name = getEndpoint().getBeanRowMapper().map(entry.getKey(), value); + properties.put(name, value); + } + try { + IntrospectionSupport.setProperties(answer, properties); + } catch (Exception e) { + throw new SQLException("Error setting properties on output class " + outputClzz, e); + } + + // check we could map all properties to the bean + if (!properties.isEmpty()) { + throw new IllegalArgumentException("Cannot map all properties to bean of type " + outputClzz + ". There are " + properties.size() + " unmapped properties. " + properties); + } + return answer; } } http://git-wip-us.apache.org/repos/asf/camel/blob/edde4da8/components/camel-jdbc/src/test/java/org/apache/camel/component/jdbc/CustomerModel.java ---------------------------------------------------------------------- diff --git a/components/camel-jdbc/src/test/java/org/apache/camel/component/jdbc/CustomerModel.java b/components/camel-jdbc/src/test/java/org/apache/camel/component/jdbc/CustomerModel.java new file mode 100644 index 0000000..cef82f4 --- /dev/null +++ b/components/camel-jdbc/src/test/java/org/apache/camel/component/jdbc/CustomerModel.java @@ -0,0 +1,39 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.jdbc; + +public class CustomerModel { + + private String id; + private String name; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/edde4da8/components/camel-jdbc/src/test/java/org/apache/camel/component/jdbc/JdbcProducerOutputTypeSelectOneOutputClassTest.java ---------------------------------------------------------------------- diff --git a/components/camel-jdbc/src/test/java/org/apache/camel/component/jdbc/JdbcProducerOutputTypeSelectOneOutputClassTest.java b/components/camel-jdbc/src/test/java/org/apache/camel/component/jdbc/JdbcProducerOutputTypeSelectOneOutputClassTest.java new file mode 100644 index 0000000..ba75b63 --- /dev/null +++ b/components/camel-jdbc/src/test/java/org/apache/camel/component/jdbc/JdbcProducerOutputTypeSelectOneOutputClassTest.java @@ -0,0 +1,51 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.jdbc; + +import org.apache.camel.EndpointInject; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.mock.MockEndpoint; +import org.junit.Test; + +public class JdbcProducerOutputTypeSelectOneOutputClassTest extends AbstractJdbcTestSupport { + + @EndpointInject(uri = "mock:result") + private MockEndpoint mock; + + @SuppressWarnings({"unchecked"}) + @Test + public void testOutputTypeSelectOneOutputClass() throws Exception { + mock.expectedMessageCount(1); + + template.sendBody("direct:start", "select * from customer where ID = 'cust1'"); + + assertMockEndpointsSatisfied(); + + CustomerModel model = assertIsInstanceOf(CustomerModel.class, mock.getReceivedExchanges().get(0).getIn().getBody(CustomerModel.class)); + assertEquals("cust1", model.getId()); + assertEquals("jstrachan", model.getName()); + } + + @Override + protected RouteBuilder createRouteBuilder() throws Exception { + return new RouteBuilder() { + public void configure() throws Exception { + from("direct:start").to("jdbc:testdb?outputType=SelectOne&outputClass=org.apache.camel.component.jdbc.CustomerModel").to("mock:result"); + } + }; + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/edde4da8/components/camel-jdbc/src/test/java/org/apache/camel/component/jdbc/JdbcProducerOutputTypeSelectOneTest.java ---------------------------------------------------------------------- diff --git a/components/camel-jdbc/src/test/java/org/apache/camel/component/jdbc/JdbcProducerOutputTypeSelectOneTest.java b/components/camel-jdbc/src/test/java/org/apache/camel/component/jdbc/JdbcProducerOutputTypeSelectOneTest.java new file mode 100644 index 0000000..345de0b --- /dev/null +++ b/components/camel-jdbc/src/test/java/org/apache/camel/component/jdbc/JdbcProducerOutputTypeSelectOneTest.java @@ -0,0 +1,53 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.jdbc; + +import java.util.Map; + +import org.apache.camel.EndpointInject; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.mock.MockEndpoint; +import org.junit.Test; + +public class JdbcProducerOutputTypeSelectOneTest extends AbstractJdbcTestSupport { + + @EndpointInject(uri = "mock:result") + private MockEndpoint mock; + + @SuppressWarnings({"unchecked"}) + @Test + public void testOutputTypeSelectOne() throws Exception { + mock.expectedMessageCount(1); + + template.sendBody("direct:start", "select * from customer where ID = 'cust1'"); + + assertMockEndpointsSatisfied(); + + Map row = assertIsInstanceOf(Map.class, mock.getReceivedExchanges().get(0).getIn().getBody(Map.class)); + assertEquals("cust1", row.get("ID")); + assertEquals("jstrachan", row.get("NAME")); + } + + @Override + protected RouteBuilder createRouteBuilder() throws Exception { + return new RouteBuilder() { + public void configure() throws Exception { + from("direct:start").to("jdbc:testdb?outputType=SelectOne").to("mock:result"); + } + }; + } +}