Hi all i am a beginner for spring i just started it.
i am getting an error
" Error creating bean with name 'question' defined in class path resource [org/collection/ApplicationContext2.xml]: 3 constructor arguments specified but no matching constructor found in bean 'question' (hint: specify index/type/name arguments for simple parameters to avoid type ambiguities)"
i have two class 1st is Question that contains a single constructor Question and the second class is Answer
i am trying to create reference of answer class and insert into the Question class which have Array List
i goggled it and found that i need to specify the type.
i have already specified it but still i am getting the error
Thanks..
Question.java
package org.collection;
import java.awt.List;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
public class Question {
private int id;
private String name;
private ArrayList<String> answers;
//private HashSet<String> answers1;
public Question()
{
//Default constructor
}
public Question(int id,String name,ArrayList<String> answers)
{
super();
this.id=id;
this.name=name;
this.answers=answers;
}
public void display()
{
System.out.println("Id :"+id+"\nName :"+name);
System.out.println("Answers are");
Iterator<String> itr= answers.iterator();
while(itr.hasNext())
{
System.out.println(itr.next());
}
/*System.out.println("----------picking up the answers from HashSet---------");
Iterator<String> itr1=answers1.iterator();
while(itr1.hasNext())
{
System.out.println(itr1.next());
}
System.out.println("-------reached-----------");*/
}
}
Answer.java
package org.collection;
public class Answer {
private int id;
private String name;
private String by;
public Answer() {
// TODO Auto-generated constructor stub
}
public Answer(int id,String name,String by)
{
super();
this.id=id;
this.name=name;
this.by=by;
}
public String toString()
{
return "ID :"+id+"\nName"+name+"\nBy :"+by;
}
}
ApplicationContext.xml2
<?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:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="ans1" class="org.collection.Answer">
<constructor-arg value="1" type="int"></constructor-arg>
<constructor-arg value="java is a progamming language hahahaha" type="java.lang.String"></constructor-arg>
<constructor-arg value ="varun" type="java.lang.String"> </constructor-arg>
</bean>
<bean id ="ans2" class="org.collection.Answer">
<constructor-arg value="2" type="int"></constructor-arg>
<constructor-arg value="java is a platfornm" type="java.lang.String"></constructor-arg>
<constructor-arg value ="Rahul" type="java.lang.String"></constructor-arg>
</bean>
<bean id="question" class= "org.collection.Question">
<constructor-arg value="111" type="int"></constructor-arg>
<constructor-arg value="What is java ?" type="java.lang.String"></constructor-arg>
<constructor-arg>
<list>
<ref bean="ans1"/>
<ref bean="ans2"/>
</list>
</constructor-arg>
</bean>
</beans>
The three parameter constructor in Question is expecting List of String. But, you are passing List of Answer. Change the third parameter in Question class to ArrayList<Answer> answers
Related
public enum TypeEnum {
TYPE1, TYPE2, TYPE3;
}
public class Resources {
List<String> suppliers;
EnumMap<TypeEnum, String> items;
//setter and getter
}
I'm in the process of replicating the above bean in spring config xml file. I'm trying as per below but struck up with EnumMap. I understand that we can try using util:map. Please help.
<bean name="products" class="com.company.xxxx.Resources">
<property name="suppliers">
<list>
<value>suppliers1</value>
<value>suppliers2</value>
<value>suppliers3</value>
</list>
</property>
//TODO
<util:map id="items" >
</util:map>
</bean>
I have an object returned from item processor.
public class PcdRateMapper
{
private Pcdrate pcdRate;
private Boolean isValidPcdRate;
public PcdRateMapper ()
{
// pcdRate = new Pcdrate ();
}
public Pcdrate getPcdRate ()
{
return pcdRate;
}
public void setPcdRate (Pcdrate pcdRate)
{
this.pcdRate = pcdRate;
}
public Boolean getIsValidPcdRate ()
{
return isValidPcdRate;
}
public void setIsValidPcdRate (Boolean isValidPcdRate)
{
this.isValidPcdRate = isValidPcdRate;
}
Now i want to extract only Pcdrate object values in my item writer. How can I do this. Currently I'm using following spring configuration but getting invalid property exception. Thanks in advance.
<
property name="lineAggregator">
<bean
class="org.springframework.batch.item.file.transform.DelimitedLineAggregator">
<property name="delimiter" value="," />
<property name=""></property>
<property name="fieldExtractor">
<bean
class="org.springframework.batch.item.file.transform.BeanWrapperFieldExtractor">
<property name=""></property>
<property name="names"
value="company, subcoy" />
</bean>
</property>
</bean>
</property>
The invalid property exception may stem from
<property name=""></property>
where the property name is an empty string. You have that twice in the code above, remove it.
Your xml structure seems to be invalid, see spring_bean_definition
to see how it should look like.
On the bean of type BeanWrapperFieldExtractor you must set the property 'names' to the names of properties that you want to extraxt, in your case 'pcdRate'.
It should be configured like this :
<bean class="org.springframework.batch.item.file.transform.BeanWrapperFieldExtractor">
<property name="names" value="pcdRate" />
</bean>
I am using spring. I need to return object based on the String. I have below code.
public class DaoFactoryImpl implements DaoFactory {
private String dbType;
private OrganizationActions organizationActions;
private ProductActions productActions;
public void setOrganizationActions(OrganizationActions org){
this.organizationActions = org;
}
public void setProductActions(ProductActions prodActions){
this.productActions = prodActions;
}
public void setDbType(String dbType){
this.dbType = dbType;
}
#Override
public OrganizationActions getDaoObject() {
if(dbType.equalsIgnoreCase("Oracle")){
return organizationActions;
}else if(dbType.equalsIgnoreCase("DB2")){
return productActions;
}
return null;
}
}
Spring_congig.xml:
<util:properties id="configProps"
location="classpath:config/config.properties" />
<bean id="orgService" class="com.sample.OrganizationMongoService">
</bean>
<bean id="productService" class="com.sample.ProductMongoService"/>
<bean id="daoFactory" class="com.sample.factory.DaoFactoryImpl">
<property name="dbType" value="${dbName}"/>
<property name="organizationActions" ref="orgService"/>
<property name="productActions" ref="productService"/>
</bean>
I specify dbName in config.properties file. I have hard coded the same dbName (Oracle, DB2) in DaoFactoryImpl class. How can I avoid hard coding Oracle, DB2 in the code. Is there anyway to specify this criteria in the spring xml file?
Try creating a map in your spring config and use it to look up the correct instance. For example:
<bean id="daoFactory" class="com.sample.factory.DaoFactoryImpl">
<property name="dbType" value="${dbName}"/>
<property name="typeMap">
<map>
<entry key="Oracle" value-ref="orgService"/>
<entry key="DB2" value-ref="productService"/>
</map>
<property>
</bean>
Then do a lookup in your factory method:
public void setTypeMap(Map<String,Actions> typeMap){
this.typeMap = typeMap;
}
#Override
public OrganizationActions getDaoObject() {
return typeMap.get(dbType);
}
You can add the below code in Spring_congig.xml:-
<bean
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location">
<value>properties/database.properties</value>
</property>
</bean>
and define your key-value pair in database.properties as:-
dbName=Oracle
Your Spring_congig.xml will pick up the required value for the given key.
<property name="dbType" value="${dbName}"/>
How to Set the argument value for a TreeSet in Spring?
public class Trainer {
String name;
TreeSet<String> batches;
public Trainer(String name, TreeSet<String> batches) {
super();
this.name = name;
this.batches = batches;
}
#Override
public String toString() {
StringBuilder x=new StringBuilder();
x.append("trainer:").append(name).append("\n");
x.append("batches:\n");
for(String a :batches)
{
x.append(a).append("\n");
}
return x.toString();
}
}
//here is the configuration file
<beans>
<bean id="abc" class="Trainer">
<constructor-arg value="asfsad"/>
<constructor-arg>
<set>
<value>kasdaskdnas</value>
<value>sjbdlsas;dkas</value>
</set>
</constructor-arg>
</bean>
</beans>
This throws an exception when trying to Create a object for it,could not convert constructor argument value of type [java.util.LinkedHashSet] to required type [java.util.TreeSet]:
You can use the util:set tag
<beans>
<bean id="abc" class="Trainer">
<constructor-arg value="asfsad" />
<constructor-arg>
<util:set set-class="java.util.TreeSet">
<value>kasdaskdnas</value>
<value>sjbdlsas;dkas</value>
</util:set>
</constructor-arg>
</bean>
</beans>
You can control the implementation of Set to be used for your Sring-managed set using the set-class attribute.
Something like this: <set set-class="java.util.TreeSet">
I am wondering how to implement batch operations with my insert statements using MyBatis 3 & Spring 3?
For example, here is what is currently being done:
spring.xml:
<bean id="jndiTemplateDatasource" class="org.springframework.jndi.JndiTemplate">
<property name="environment">
<props>
<prop key="java.naming.factory.initial">${context.factory}</prop>
</props>
</property>
</bean>
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiTemplate" ref="jndiTemplateDatasource"/>
<property name="jndiName" value="${connectionpool.jndi}"/>
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation" value="classpath:mybatis-config.xml"/>
</bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.test" />
</bean>
MyService.xml:
<insert id="insertMyRecord" parameterType="com.test.MyRecord" >
insert into ... // code removed
</insert>
MyService.java:
public interface MyService {
public void insertMyRecord (MyRecord);
}
MyController.java:
#Controller
public class MyController {
#Autowired
private MyService myService;
#Transactional
#RequestMapping( .... )
public void bulkUpload (#RequestBody List<MyRecord> myRecords) {
for (MyRecord record : myRecords) {
myService.insertMyRecord(record);
}
}
}
Disclaimer: That is just pseudo code for demonstration purposes
So what can I do to turn that into a batch process?
Ideally I want to be able to do it with least "intrusion" into code, i.e. use annotations more preferred, but if not possible what is the next best thing?
Also, this needs to be configured just for this one service, not for everything in the project.
The accepted answer above doesn't actually get you batch mode for MyBatis. You need to choose the proper Executor via ExecutorType.BATCH. That is either passed as a parameter to SqlSession.openSession in standard MyBatis API or, if using MyBatis-Spring, as an option to the SqlSessionTemplate. That is done via:
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg index="0" ref="sqlSessionFactory" />
<constructor-arg index="1" value="BATCH" />
</bean>
There is nothing else that needs to be done.
This is running and tested example ...
Update multiple rows using batch (ibatis + java )
In this ex. I am updating attending count from table with respective to partyid.
public static int updateBatch(List<MyModel> attendingUsrList) {
SqlSession session = ConnectionBuilderAction.getSqlSession();
PartyDao partyDao = session.getMapper(PartyDao.class);
try {
if (attendingUsrList.size() > 0) {
partyDao.updateAttendingCountForParties(attendingUsrList);
}
session.commit();
} catch (Throwable t) {
session.rollback();
logger.error("Exception occurred during updateBatch : ", t);
throw new PersistenceException(t);
} finally {
session.close();
}
}
Model class where variable is defined :
public class MyModel {
private long attending_count;
private String eid;
public String getEid() {
return eid;
}
public void setEid(String eid) {
this.eid = eid;
}
public long getAttending_count() {
return attending_count;
}
public void setAttending_count(long attending_count) {
this.attending_count = attending_count;
}
}
party.xml code
Actual query where batch execute
<foreach collection="attendingUsrList" item="model" separator=";">
UPDATE parties SET attending_user_count = #{model.attending_count}
WHERE fb_party_id = #{model.eid}
</foreach>
Interface code here
public interface PartyDao {
int updateAttendingCountForParties (#Param("attendingUsrList") List<FBEventModel>attendingUsrList);
}
Here is my batch session code
public static synchronized SqlSession getSqlBatchSession() {
ConnectionBuilderAction connection = new ConnectionBuilderAction();
sf = connection.getConnection();
SqlSession session = sf.openSession(ExecutorType.BATCH);
return session;
}
SqlSession session = ConnectionBuilderAction.getSqlSession();
I'm not sure I understand the question fully correct but I will try to give you my thoughts.
For making the single service I would recommend to generify the service interface:
public void bulkUpload (#RequestBody List<T> myRecords)
Then you can check the type of the object and call the propper mapper repository.
Then you can generify it more by creating a common interface:
public interface Creator<T> {
void create(T object);
}
and extend it by your mapper interface:
public interface MyService extends Creator<MyRecord>{}
Now the most complicated step: you get the object of a particular type, see what exact mapper implements the Creator interface for this class (using java reflection API) and invoke the particular method.
Now I give you the code I use in one of my projects:
package com.mydomain.repository;
//imports ...
import org.reflections.Reflections;
#Repository(value = "dao")
public class MyBatisDao {
private static final Reflections REFLECTIONS = new Reflections("com.mydomain");
#Autowired
public SqlSessionManager sqlSessionManager;
public void create(Object o) {
Creator creator = getSpecialMapper(Creator.class, o);
creator.create(o);
}
// other CRUD methods
#SuppressWarnings("unchecked")
private <T> T getSpecialMapper(Class<T> specialClass, Object parameterObject) {
Class parameterClass = parameterObject.getClass();
Class<T> mapperClass = getSubInterfaceParametrizedWith(specialClass, parameterClass);
return sqlSessionManager.getMapper(mapperClass);
}
private static <T, P> Class<? extends T> getSubInterfaceParametrizedWith(Class<T> superInterface, Class<P> parameterType) {
Set<Class<? extends T>> subInterfaces = REFLECTIONS.getSubTypesOf(superInterface);
for (Class<? extends T> subInterface: subInterfaces) {
for (Type genericInterface : subInterface.getGenericInterfaces()) {
if (!(genericInterface instanceof ParameterizedType)) continue;
ParameterizedType parameterizedType = (ParameterizedType) genericInterface;
Type rawType = parameterizedType.getRawType();
if (rawType instanceof Class<?> && ((Class<?>) rawType).isAssignableFrom(superInterface)) {
for (Type type: parameterizedType.getActualTypeArguments()) {
if (type instanceof Class<?> && ((Class<?>) type).isAssignableFrom(parameterType)) {
return subInterface;
}
}
}
}
}
throw new IllegalStateException(String.format("No extension of %s found for parametrized type %s ", superInterface, parameterType));
}
}
Warning! This approach can have bad performance impact so use it in non-performance-critical actions
If you want bulk insert I would recommend to use mybatis foreach for bulk insert as described here.
If you think you don't want to write sql for every type of objects you better use Hibernate or any other advanced ORM. MyBatis is just an SQL mapping interface.