HttpMessageConverter not found in Spring restTemplate - spring

I have got error when I retrieve JSON using String restTempate. Error says
Could not extract response: no suitable HttpMessageConverter found for response type [class au.org.jeenee.mdm.models.PhoneResponse] and content type [application/json]
at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:107)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:492)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:447)
at org.springframework.web.client.RestTemplate.postForObject(RestTemplate.java:295)
at au.org.jeenee.mdm.services.EccClientServiceImpl.findPhoneByImei(EccClientServiceImpl.java:51)
at au.org.jeenee.mdm.controllers.DeviceController.showEditForm(DeviceController.java:308)
I found out the message means there is no JSON converter registered but I have Jackson message converter in my xml.
applicationContext.xml
<bean id="jacksonMessageConverter"
class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter" />
<bean
class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<ref bean="jacksonMessageConverter" />
</list>
</property>
</bean>
<bean id="restTemplate" class="org.springframework.web.client.RestTemplate">
<constructor-arg>
<bean class="org.springframework.http.client.HttpComponentsClientHttpRequestFactory">
<constructor-arg ref="httpClient"/>
</bean>
</constructor-arg>
<property name="messageConverters">
<list>
<ref bean="jacksonMessageConverter" />
</list>
</property>
</bean>
And here is my code to use RestTemplate.
public class MyRestClientService {
#Override
public List<DeviceHolder> findDeviceHoldersByUserId(String userId) {
String uri = "/web/getpersonlist?userId=" + userId;
try {
DeviceHolderResponse response = restClient.getRestTemplate().postForObject(restClient.createUrl(uri), "", DeviceHolderResponse.class);
if (response!=null && response.isOk() && response.getResult()!=null){
DeviceHolder[] deviceHolders = response.getResult();
return Arrays.asList(deviceHolders);
}
} catch (Exception e) {
e.printStackTrace();
}
return Collections.emptyList();
}
#Override
public Phone findPhoneByImei(String imei) {
log.info("findPhoneByImei:" + imei);
Phone phone = null;
String uri = "/ecc/getphoneplan?imei=" + imei;
try {
PhoneResponse response = restClient.getRestTemplate().postForObject(restClient.createUrl(uri), "", PhoneResponse.class);
if (response.getResult()!=null)
phone = response.getResult();
} catch (Exception e) {
e.printStackTrace();
}
return phone;
}
}
PhoneResponse.java
public class Phone implement Serializable {
private boolean ok;
private String message;
private Phone result;
//getters and setters
}
Phone.java
public class Phone implements Serializable {
#JsonProperty(value="phoneid")
private long phoneId;
private Plan plan;
private String sim;
private String imei;
#JsonProperty(value="phonetype")
private String phoneType;
#JsonProperty(value="phonenumber")
private String phoneNumber;
private String label;
#JsonProperty(value="connecteddate")
private String connectedDate;
//getters and setters
}
Plan.java
public class Plan implements Serializable {
#JsonProperty(value="planid")
private long planId;
#JsonProperty(value="planname")
private String planName;
private double billingIncrement;
private double owiStdUnitCost;
private double owiFlagFall;
private double stdCap;
private double dataCap;
private double smsCap;
private double owiDataUnitCost;
private double owiSms;
//getters and setters
}
And the response packet is like following:
{
"ok": true,
"message": "",
"result":
{
"phoneid": 600003,
"phonenumber": 478439503,
"phonetype": "Samsung Galaxy S2",
"imei": "1111111111",
"sim": "1111111111",
"label": "Person name",
"connecteddate": "2012-09-19 00:00:00.0",
"plan":
{
"planid": 34,
"planname": "$59 Plan",
"billingIncrement": 30,
"owiStdUnitCost": 81.8181818181818,
"owiFlagFall": 0,
"stdCap": 636.3636,
"dataCap": 227.2665,
"smsCap": 1363.638,
"owiDataUnitCost": 0.022194,
"owiSms": 22.7272727272727
}
}
}
Strangely, there is no error when I call findDeviceHoldersByUserId method but error for findPhoneByImei method. And this has been working up to just before.
I tried again and again but I still have the error. Please help to fix the problem.
Thanks.

Couple of reasons, I found, that can cause this issue are -
Data type of the setters/getters are different from that of the actual properties (also mentioned in comment of sunghun)
If there are overloaded methods that may look like setter/getter of a field - same name as setField or getField where field is a property of the class.
I had a field private boolean success and 2 setter methods -
public void setSuccess(List<Object> dataList);
public void setSuccess(boolean success);
On debugging, I found that class com.fasterxml.jackson.databind.deser.BeanDeserializerFactory was throwing an exception. This exception was suppressed within Jackson's lib and the exception thrown by the RestTemplate was the same as the subject.
java.lang.IllegalArgumentException: Conflicting setter definitions for property "failure": com.test.dto.JsonResponse#setFailure(1 params) vs com.test.dto.JsonResponse#setFailure(1 params)
I changed the method to public void setSuccessData(List<Object> dataList); and it worked fine.
Hope this helps someone.

Related

populate enum fields with application.properties and java configuration

with spring xml configuration, it is possible to define the following in app context xml to populate the status field in the TestEnum:
app context xml
<bean id="blue" class="com.example.demo.test.TestEnum" factory-method="valueOf">
<property name="status" value="${testnum.blue.status}"/>
<constructor-arg>
<value>BLUE</value>
</constructor-arg>
</bean>
<bean id="red" class="com.example.demo.test.TestEnum" factory-method="valueOf">
<property name="status" value="${testnum.red.status}"/>
<constructor-arg>
<value>RED</value>
</constructor-arg>
</bean>
enum class
public enum TestEnum {
BLUE,
RED;
private String status;
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
}
mystatus.properties
testnum.blue.status=good
testnum.red.status=bad
Is this possible with spring boot using application.properties + java configuration without xml?
Yes, a simple environment configuration class (annotated with #ConfigurationProperties for example), will map and do the conversion of your enum automatically.
Example:
#Configuration
#Validated
#ConfigurationProperties(prefix = "my.property.path")
public class TestConfiguration{
public enum TestEnum {
BLUE, RED
}
#NotNull
private TestEnum type;
public TestConfiguration() {
}
public #NotNull TestEnum getType() {
return this.type;
}
public void setType(#NotNull TestEnum type) {
this.type = type;
}
}

Implement interface in runtime Java EE and Spring

I would like to implement the interface at runtime based on variable.
Example :
Class A implements interface1 {
public getValue() {}
}
Class B implements interface1 {
public getValue() {}
}
So I would like to have variable sitting in configuration..., for example ClasstoImplement=A
So, if ClasstoImplement=A, then I need to call Class A.getValue()
If ClasstoImplement=B, then I need to call Class B.getValue() at runtime. And I should be able to change value of ClasstoImplement at runtime.
My application is Spring based and runs in Tomcat.
Can someone please help me to find out if there is any way??
There are many possible solutions. The one of them is to use org.springframework.aop.target.HotSwappableTargetSource.
take a look at implementation that could be considered:
public class CustomSwappable<T> implements Interface1 {
private HotSwappableTargetSource targetSource;
private String key;
private Map<String, T> swappableBeans;
#PostConstruct
private void init() {
targetSource = new HotSwappableTargetSource(swappableBeans.values().iterator().next()); // first is the default
}
// you need to track changes in config and call this method if any modifications were done
public void configChanged(String key, String value) {
if (!this.key.equals(key)) {
return;
}
if (!swappableBeans.containsKey(value)) {
return;
}
targetSource.swap(swappableBeans.get(value));
}
#Override
public String getValue() {
return ((Interface1)targetSource.getTarget()).execute();
}
#Required
public void setConfigurationKey(String key) {
this.key = key;
}
#Required
public void setSwappableBeans(Map<String, T> swappableBeans) {
this.swappableBeans = swappableBeans;
}
}
and bean declaration should as follows:
<bean id="Interface1Swappable" class="path.to.CustomSwappable">
<property name="configurationKey" value="swappableKey"/>
<property name="swappableBeans">
<util:map value-type="path.toInterface1">
<!-- first is default -->
<entry key="classA">
<bean class="path.to.class.A"/>
</entry>
<entry key="classB">
<bean class="path.to.class.B"/>
</entry>
</util:map>
</property>
</bean>

Batch insertion with Spring MVC and Hibernate 3

I am using Spring MVC + Hibernate and try to save bulk record using "hibernate batch procession technique" but getting below exception when I am doing session.flush() and session.clear().
org.hibernate.LazyInitializationException: could not initialize proxy - no Session
following is my code sample
DaoImpl method
#SuppressWarnings("unchecked")
#Override
public String transferPsalesDataToMisSales() {
Session session = null;
Transaction tx=null;
String result="failed";
try {session = this.getSessionFactory().openSession();
tx = session.beginTransaction();
Criteria criteria=session.createCriteria(PsalesInfo.class);
List<PsalesInfo> pSalesData=criteria.list();
if(pSalesData.size() >0){
Iterator<PsalesInfo> it=pSalesData.iterator();
int index=0;
MisSalesInfo mis=null;
while(it.hasNext()){
mis=new MisSalesInfo();
PsalesInfo psales=it.next();
StockistInfo stockistInfo=psales.getStockistInfo();
TalukaInfo talukaInfo=stockistInfo.getTalukaInfo();
IsrInfo isr=(IsrInfo) session.get(IsrInfo.class, stockistInfo.getIsrId());
//mis settters
mis.setMisSalesId(psales.getPsalesId());
mis.setStateName(talukaInfo.getDistrictInfo().getStateInfo().getStateName());
mis.setDistName(talukaInfo.getDistrictInfo().getDistName());
mis.setTalukaName(talukaInfo.getTalukaName());
mis.setAsmId(talukaInfo.getAsmInfo().getAsmId());
mis.setTsoId(stockistInfo.getTsoInfo().getTsoId());
if(null!=isr){
mis.setIsrId(isr.getIsrId());
mis.setIsrName(isr.getIsrName());
}
mis.setUnitNo(stockistInfo.getUnitNo());
mis.setBillNo(psales.getBillNo());
session.save(mis);
if(index % 50==0){
//flush a batch of inserts and release memory:
session.flush();
session.clear();
}
index++;
}//end of while
tx.commit();
result=pSalesData.size()+" Psales are Successfully transfered to MIS Sales";
}
else{
result="No Psales is available to transfer since are already available in MIS Sales";
}
} catch (HibernateException e) {
tx.rollback();
logger.error("error in MasterDaoImpl transfer data:"+e);
}finally {
if (null != session)
session.close();
}
return result;
}
POJOs
#Entity
#Table(name = "psales_info", catalog = "secondary_sales")
public class PsalesInfo implements java.io.Serializable {
private static final long serialVersionUID = 5578632011679493005L;
private Integer psalesId;
private StockistInfo stockistInfo;
//and some other attributes
//getter and setters
#Id
#GenericGenerator(name="generator", strategy="increment")
#GeneratedValue(generator="generator")
#Column(name = "psales_id", unique = true, nullable = false)
public Integer getPsalesId() {
return this.psalesId;
}
public void setPsalesId(Integer psalesId) {
this.psalesId = psalesId;
}
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "pcode", nullable = false)
public StockistInfo getStockistInfo() {
return this.stockistInfo;
}
//and others
#Entity
#Table(name = "stockist_info", catalog = "secondary_sales")
public class StockistInfo implements java.io.Serializable {
private String stockistId;
private TalukaInfo talukaInfo;
//and rest attributes
//getters and setters
// Property accessors
#Id
#Column(name = "stockist_id", unique = true, nullable = false, length = 10)
public String getStockistId() {
return this.stockistId;
}
public void setStockistId(String stockistId) {
this.stockistId = stockistId;
}
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "taluka_sid", nullable = false)
public TalukaInfo getTalukaInfo() {
return this.talukaInfo;
}
ServiceImpl
#Service
#Transactional
public class TransactionServiceImpl implements TransactionService {
#Autowired
private TransactionDAO transactionDAO;
#Override
public String transferPsalesDataToMisSales() {
return this.getTransactionDAO().transferPsalesDataToMisSales();
}
}
dispature-servlet.xml
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="configLocation" value="classpath:hibernate.cfg.xml"/>
<property name="configurationClass" value="org.hibernate.cfg.AnnotationConfiguration"/>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
<prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>
<prop key="hibernate.default_catalog">${hibernate.default_catalog}</prop>
<prop key="hibernate.jdbc.batch_size">50</prop>
</props>
</property>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager"
p:sessionFactory-ref="sessionFactory"/>
Need help here why it is throwing LazyInitializationException when I'm clearing the session.
But when I'm not clearing the session ie. wihtout session.clear() and session.flush() application is running properly.
but I know it may lead to OutOfMemoryException in case of more bulk record.
so plz tell how to deal with this situation now?
Your dao code is flawed... Don't open new sessions yourself and don't mess aroudn with transactions yourself either. Remove the transaction stuff from your dao method and the call to openSession should be replaced with getCurrentSession.
#SuppressWarnings("unchecked")
#Override
public String transferPsalesDataToMisSales() {
Session session = this.getSessionFactory().getCurrentSession();
Criteria criteria=session.createCriteria(PsalesInfo.class);
List<PsalesInfo> pSalesData=criteria.list();
int index=0;
for (PsalesInfo psales : pSalesData) {
MisSalesInfo mis=new MisSalesInfo();
StockistInfo stockistInfo=psales.getStockistInfo();
TalukaInfo talukaInfo=stockistInfo.getTalukaInfo();
IsrInfo isr=(IsrInfo) session.get(IsrInfo.class, stockistInfo.getIsrId());
//mis settters
mis.setMisSalesId(psales.getPsalesId());
mis.setStateName(talukaInfo.getDistrictInfo().getStateInfo().getStateName());
mis.setDistName(talukaInfo.getDistrictInfo().getDistName());
mis.setTalukaName(talukaInfo.getTalukaName());
mis.setAsmId(talukaInfo.getAsmInfo().getAsmId());
mis.setTsoId(stockistInfo.getTsoInfo().getTsoId());
if(null!=isr){
mis.setIsrId(isr.getIsrId());
mis.setIsrName(isr.getIsrName());
}
mis.setUnitNo(stockistInfo.getUnitNo());
mis.setBillNo(psales.getBillNo());
session.save(mis);
if(index % 50==0){
//flush a batch of inserts and release memory:
session.flush();
session.clear();
}
index++;
}//end of loop
if (pSalesData.isEmpty() ) {
return "No Psales is available to transfer since are already available in MIS Sales";
} else {
return pSalesData.size()+" Psales are Successfully transfered to MIS Sales";
}
}

Autowiring String property through application context

I want to autowire a String bean as below
<bean id="name" class="java.lang.String" autowire="byName">
<constructor-arg value="Aravind"/>
</bean>
<bean id="employee" class="Employee" autowire="byName"/>
public Class Employee
{
private String name;
public void setName(String name)
{
this.name=name;
}
public String getName()
{
return name;
}
}
When I try to access the name attribute in the employee is null
Employee emp=(Employee)getApplicationContext().getBean("employee");
System.out.println(emp.getName()==null);
It prints true.
Can someone help on this?
You still need to set the property on the Employee somehow.
Setting the name can be done in multiple ways.
XML configuration.
<bean id="employee" class="Employee" autowire="byName">
<property name="name">
<ref bean="name" />
</property>
</bean>
Using #Autowired
public Class Employee {
#Autowired
private String name;
public void setName(String name) {
this.name=name;
}
public String getName() {
return name;
}
}

Where I did wrong? Why PropertEditorSupport is not working for me?

Why I am getting action in PropertyEditorSupport? Could anyone please help me here because i am new in Spring. Below is the error report
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'cont' defined in class path resource [propertyEdit.xml]: Initialization of bean failed; nested exception is org.springframework.beans.TypeMismatchException: Failed to convert property value of type [java.lang.String] to required type [Phone] for property 'phone'; nested exception is java.lang.IllegalArgumentException: 888-555-1212
Caused by: org.springframework.beans.TypeMismatchException: Failed to convert property value of type [java.lang.String] to required type [Phone] for property 'phone'; nested
exception is java.lang.IllegalArgumentException: 888-555-1212
Caused by: java.lang.IllegalArgumentException: 888-555-1212
at java.beans.PropertyEditorSupport.setAsText(Unknown Source)
at org.springframework.beans.TypeConverterDelegate.doConvertTextValue(TypeConverterDelegate.java:326)
at org.springframework.beans.TypeConverterDelegate.doConvertValue(TypeConverterDelegate.java:305)
at org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:192)
at org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:138)
at org.springframework.beans.BeanWrapperImpl.convertForProperty(BeanWrapperImpl.java:380)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1111)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:861)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:421)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:251)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:156)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:248)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:160)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:287)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:352)
at org.springframework.context.support.ClassPathXmlApplicationContext.(ClassPathXmlApplicationContext.java:91)
at org.springframework.context.support.ClassPathXmlApplicationContext.(ClassPathXmlApplicationContext.java:75)
at org.springframework.context.support.ClassPathXmlApplicationContext.(ClassPathXmlApplicationContext.java:65)
at ShowContact.main(ShowContact.java:9)
I have used java.beans.PropertyEditorSupport in below way
public class PhoneEditor extends java.beans.PropertyEditorSupport{
public void setAsTest(String textValue)
{
String stripped = stripNonNumeric(textValue);
String areaCode=stripped.substring(0,3);
String prefix=stripped.substring(3,6);
String number=stripped.substring(6);
Phone phone=new Phone(areaCode,prefix,number);
setValue(phone);
}
private String stripNonNumeric(String original)
{
StringBuffer allNumeric = new StringBuffer();
for(int i=0; i<original.length(); i++)
{
char c=original.charAt(i);
if(Character.isDigit(c))
{
allNumeric.append(c);
}
}
return allNumeric.toString();
}
}
My Config file is below
<bean name="customEditorConfigurer" class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="customEditors">
<map>
<entry key="Phone">
<bean id="Phone" class="PhoneEditor">
</bean>
</entry>
</map>
</property>
</bean>
<bean id="cont" class="Contact">
<property name="name" value="Dhirendra"/>
<property name="phone" value="888-555-1212" />
</bean>
</beans>
Phone Class is below
public class Phone {
private String areaCode;
private String prefix;
private String number;
public Phone(){}
public Phone(String areaCode, String prefix, String number)
{
this.areaCode=areaCode;
this.prefix=prefix;
this.number=number;
}
public String getPhoneNumber()
{
return prefix+"-"+areaCode+"-"+number;
}
}
I am calling in the below way
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.beans.factory.config.CustomEditorConfigurer;
public class ShowContact {
public static void main(String[] args)
{
ApplicationContext context = new ClassPathXmlApplicationContext("propertyEdit.xml");
Employee employee=(Employee)context.getBean("cont");
employee.PrintEmpDetails();
}
}
Below is my Contact class which is calling
public class Contact implements Employee {
private Phone phone;
private String name;
public void setPhone(Phone phone) {
// TODO Auto-generated method stub
this.phone=phone;
}
public void setName(String name) {
// TODO Auto-generated method stub
this.name=name;
}
public void PrintEmpDetails()
{
System.out.println("Name of Employee :"+ name);
System.out.println("Contact Number of Employee :"+ phone.getPhoneNumber());
}
}
In PhoneEditor, you've implemented setAsTest, rather than overriding setAsText. As a result, Spring is calling the setAsText implementation in PropertyEditorSupport, which throws the exception.
This is why you should always use #Override annotations, and set your compiler to at least report a warning if you don't do it.
The problem is that you have a typo in your class. It's setAsText, not setAsTest:
#Override
public void setAsText(String textValue) throws IllegalArgumentException {
final String stripped = stripNonNumeric(textValue);
final String areaCode=stripped.substring(0,3);
final String prefix=stripped.substring(3,6);
final String number=stripped.substring(6);
final Phone phone=new Phone(areaCode,prefix,number);
setValue(phone);
}
(always use #Override, as skaffman suggested)

Resources