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

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)

Related

Setter Dependency Injection with Array of String

To test the setter dependency injection with an Array of string, I wrote the below-given code -
Pojo class is -
package com.abhishek.ioc.array;
public class Person {
private int id;
private String name;
private String[] hobbies;
public void showHobbies() {
System.out.println("Person name is - "+name+", id is - "+id);
for (int i = 0; i < hobbies.length; i++) {
System.out.println(hobbies[i]);
}
}
public void setId(int id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public void setHobbies(String[] hobbies) {
this.hobbies = hobbies;
}
}
spring.xml file is -
<beans>
<bean id="person" class="com.abhishek.ioc.array.Person">
<property name="id" value="1"></property>
<property name="name" value="Abhisshek"></property>
<property name="hobbies">
<set>
<value>Playing cricket</value>
<value>Coding</value>
<value>Reading books</value>
</set>
</property>
</bean>
</beans>
Client code is -
package com.abhishek.ioc.array;
public class Client {
public static void main(String[] args) {
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("resources/spring.xml");
System.out.println("Creating Person object");
Person person = (Person)applicationContext.getBean("person");
System.out.println("Person object created");
person.showHobbies();
}
}
In spring.xml file, I tried tags <array>, <list> and <set> to inject data in array and all three tags are giving the correct result. How?

Spring Boot JPA repositories custom query

http://spring.io/guides/gs/accessing-data-jpa/
Referred the above link to define a custom query.
We have a developed a Spring boot web service CRUD application but we are facing the following exception when we add a custom query.
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'EmployeeController': Unsatisfied dependency expressed through field 'EmployeeService'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'EmployeeServiceImpl': Unsatisfied dependency expressed through field 'EmployeeRepository'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'EmployeeRepository': Invocation of init method failed; nested exception is org.springframework.data.mapping.PropertyReferenceException: No property name found for type Employee!
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:588) ~[spring-beans-4.3.9.RELEASE.jar:4.3.9.RELEASE]
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'EmployeeServiceImpl': Unsatisfied dependency expressed through field 'EmployeeRepository'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'EmployeeRepository': Invocation of init method failed; nested exception is org.springframework.data.mapping.PropertyReferenceException: No property name found for type Employee!
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:588) ~[spring-beans-4.3.9.RELEASE.jar:4.3.9.RELEASE]
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'EmployeeRepository': Invocation of init method failed; nested exception is org.springframework.data.mapping.PropertyReferenceException: No property name found for type Employee!
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1628) ~[spring-beans-4.3.9.RELEASE.jar:4.3.9.RELEASE]
Caused by: org.springframework.data.mapping.PropertyReferenceException: No property name found for type Employee!
at org.springframework.data.mapping.PropertyPath.<init>(PropertyPath.java:77) ~[spring-data-commons-1.13.4.RELEASE.jar:naat org.springframework.data.mapping.PropertyPath.create(PropertyPath.java:309) ~[spring-data-commons-1.13.4.RELEASE.jar:na]
at org.springframework.data.mapping.PropertyPath.from(PropertyPath.java:272) ~[spring-data-commons-1.13.4.RELEASE.jar:na]
This was the repository interface that I have defined. Defined a custom query.
package com.example.rest.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import com.example.rest.model.Employee;
#Repository
public interface EmployeeRepository extends JpaRepository<Employee, Long> {
Employee findByName(String employeeName);}
This is my service interface
package com.example.rest.service;
import java.util.List;
import com.example.rest.model.Employee;
public interface EmployeeService {
Employee save(Employee employee);
Employee getById(Long employeeId);
void delete(Long employeeId);
List<Employee> findAll();
Employee findByName(String employeeName); }
This is my Service Implementation class
package com.example.rest.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.example.rest.model.Employee;
import com.example.rest.repository.EmployeeRepository;
#Service
public class EmployeeServiceImpl implements EmployeeService {
#Autowired
EmployeeRepository employeeRepository;
#Override
public Employee save(Employee employee) {
// TODO Auto-generated method stub
return employeeRepository.save(employee);
}
#Override
public Employee getById(Long employeeId) {
// TODO Auto-generated method stub
return employeeRepository.getOne(employeeId);
}
#Override
public void delete(Long employeeId) {
// TODO Auto-generated method stub
employeeRepository.delete(employeeId);
}
#Override
public List<Employee> findAll() {
// TODO Auto-generated method stub
return employeeRepository.findAll();
}
#Override
public Employee findByName(String employeeName) {
// TODO Auto-generated method stub
return employeeRepository.findByName(employeeName);
}}
Without custom query my application works fine.
Let me know where I have made a mistake.
I have added the model class
package com.example.rest.model;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
#Entity
#Table(name="testF")
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(nullable=false, unique=true)
private Long employeeId;
#Column(nullable=false, unique=true)
private String employeeName;
#Column(nullable=false)
private String emailId;
#Column(nullable=false)
private Long salary;
public Employee() {
}
public Employee(Long employeeId, String employeeName, String emailId, Long salary) {
this.employeeId = employeeId;
this.employeeName = employeeName;
this.emailId = emailId;
this.salary = salary;
}
public Long getEmployeeId() {
return employeeId;
}
public void setEmployeeId(Long employeeId) {
this.employeeId = employeeId;
}
public String getEmployeeName() {
return employeeName;
}
public void setEmployeeName(String employeeName) {
this.employeeName = employeeName;
}
public String getEmailId() {
return emailId;
}
public void setEmailId(String emailId) {
this.emailId = emailId;
}
public Long getSalary() {
return salary;
}
public void setSalary(Long salary) {
this.salary = salary;
}
#Override
public String toString() {
return "Employee [employeeId=" + employeeId + ", employeeName=" + employeeName + ", emailId=" + emailId
+ ", salary=" + salary + "]";
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((employeeId == null) ? 0 : employeeId.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Employee other = (Employee) obj;
if (employeeId == null) {
if (other.employeeId != null)
return false;
} else if (!employeeId.equals(other.employeeId))
return false;
return true;
}}
you don't have field 'name' in class Employee.
spring data try created query for search Employee with field name.
Employee findByName(String employeeName);}
Your model doesn't have name property, you have employeeName, so your query should look like this:
Employee findByEmployeeName(String employeeName);
Please see reference for more info on how to build Spring Data queries. In short, when you want to create a query you have to specify full field name how it is written in your Entity.
u can't write findByName in your custom query because u don't have a name field however u can write EmployeeName

Autowire based on a condition when xml bean configuration is used

I am working on Spring auto wiring using spring configuration file(xml configuration). I want to inject beans based on a condition.
Let me go into details.
There are two classes 'EmailSender' and 'SmsSender' which implement the interface IMessageSender. Beans are configured for both classes in the configurations file.
I have another class SenderUser which has a instance variable of type IMessageSender in it.
package org.pradeep.core;
public class SenderUser {
private String name;
private String Type;
private IMessageSender msg;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return Type;
}
public void setType(String type) {
Type = type;
}
public IMessageSender getMsg() {
return msg;
}
public void setMsg(IMessageSender msg) {
this.msg = msg;
}
}
I want to inject IMessageSender into bean of SenderUser based on the value of SenderUser.getType(). That means first SernderUser.type should be set and then based on it's value (if value is 'email' then bean with the name 'email' should be wired else bean with the name 'sms' should be wired.) msg should be wired.
Please help me resolve the issue.
I believe the best approach is to implement a BeanFactory for SenderUser. Take a look at this post for an idea.
Interfaces can't be injected, they aren't beans/instances.
you may use SPEL
<bean id="user" class="SenderUser" autowire="byType">
<property name="type" value="email"/>
<property name="msg" value="#{type != null && type == 'email' ? email : sms}"/>
</bean>
<bean id="email" class="EmailSender"/>
<bean id="sms" class="SmsSender"/>

Exception in thread "main" org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'std' defined in file

package com.nareshit.beans;
public class Address {
private String city,state;
public String toString()
{
return "\n city:"+city+"\nstate:"+state;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
}
package com.nareshit.clients;
import java.awt.Container;
import java.beans.Beans;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import com.nareshit.beans.Student;
public class Test {
public static void main(String[] args)
{
BeanFactory factory=new XmlBeanFactory(new ClassPathResource("MyBeans.xml"));
Student std1=(Student)factory.getBean("std");
std1.getStudentDetails();
}
}
package com.nareshit.beans;
public class Student {
private int sid;
private String name;
private String address;
public void getStudentDetails()
{
System.out.println("student id:"+sid);
System.out.println("student name:"+name);
System.out.println("student address:"+address);
}
public int getSid() {
return sid;
}
public void setSid(int sid) {
this.sid = sid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN"
"http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
<bean id="std" class="com.nareshit.beans.Student">
<property name="std" value="1001"/>
<property name="name" value="mitu"/>
<property name="address" ref="addressObj"/>
</bean>
<bean id="addressObj" class="com.nareshit.beans.Address">
<property name="city" value="bam"/>
<property name="state" value="odisha"/>
</bean>
</beans>
This is the spring setter injection prog. where i am getting error:
Exception in thread "main" org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'std' defined in file("")
how to solve it?
Please see com.nareshit.beans.Student class. It is having one property named as address which is a type of String. When you are writing the XML,
you are giving one reference type of com.nareshit.beans.Address.
Solution :
1. You can give a String value in the XML for address property.like
ddress property like
<bean id="std" class="com.nareshit.beans.Student">
<property name="std" value="1001"/>
<property name="name" value="mitu"/>
<property name="address" value="SOME ADDRESS"/>
</bean>
2. You can change the type of address property in Student Class like
public class Student{
Address address;
//declaration of rest property
//Some Boiler Plate Code
}

Why do I get a "No property node found on entity class … to bind constructor parameter to!" with Spring Data MongoDB

Trying to use JodaTime's LocalDate with Spring Data MongoDB and Spring 4 but I am getting the following exception:
SEVERE: Servlet.service() for servlet [dispatcher] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.data.mapping.model.MappingException: No property node found on entity class com.th.model.Price to bind constructor parameter to!] with root cause
org.springframework.data.mapping.model.MappingException: No property node found on entity class com.th.model.Price to bind constructor parameter to!
at org.springframework.data.mapping.model.PersistentEntityParameterValueProvider.getParameterValue(PersistentEntityParameterValueProvider.java:74)
at org.springframework.data.mapping.model.SpELExpressionParameterValueProvider.getParameterValue(SpELExpressionParameterValueProvider.java:63)
at org.springframework.data.convert.ReflectionEntityInstantiator.createInstance(ReflectionEntityInstantiator.java:71)
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:249)
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:230)
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:190)
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:186)
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:77)
at org.springframework.data.mongodb.core.MongoTemplate$ReadDbObjectCallback.doWith(MongoTemplate.java:2121)
at org.springframework.data.mongodb.core.MongoTemplate.executeFindMultiInternal(MongoTemplate.java:1805)
at org.springframework.data.mongodb.core.MongoTemplate.doFind(MongoTemplate.java:1628)
at org.springframework.data.mongodb.core.MongoTemplate.doFind(MongoTemplate.java:1611)
at org.springframework.data.mongodb.core.MongoTemplate.find(MongoTemplate.java:535)
at org.springframework.data.mongodb.core.MongoTemplate.find(MongoTemplate.java:526)
at com.th.model.Company.getPrices(Company.java:255)
at com.th.controller.Home.getPrices(Home.java:32)
…
Here my configuration:
<mongo:db-factory id="mongoDbFactory" dbname="th" host="localhost"/>
<mongo:mapping-converter id="mappingConverter">
<mongo:custom-converters>
<mongo:converter>
<bean class="com.th.tool.MongoDBConverters.DateToLocalDateConverter"/>
</mongo:converter>
<mongo:converter>
<bean class="com.th.tool.MongoDBConverters.LocalDateToDateConverter"/>
</mongo:converter>
</mongo:custom-converters>
</mongo:mapping-converter>
<bean class="org.springframework.data.mongodb.core.MongoTemplate">
<constructor-arg name="mongoDbFactory" ref="mongoDbFactory"/>
<constructor-arg name="mongoConverter" ref="mappingConverter"/>
</bean>
public class MongoDBConverters {
public static class DateToLocalDateConverter implements Converter<Date, LocalDate> {
#Override
public LocalDate convert(Date source) {
return source == null ? null : LocalDate.fromDateFields(source);
}
}
public static class LocalDateToDateConverter implements Converter<LocalDate, Date> {
#Override
public Date convert(LocalDate source) {
return source == null ? null : source.toDate();
}
}
}
Apparently I can't have a constructor like this:
public Price(String companyId, JsonNode node) {
this.companyId = companyId;
if(node != null) {
this.date = Tools.getLocalDate(node.get("Date").getTextValue());
this.closePrice = Double.parseDouble(node.get("Close").getTextValue());
this.volume = Double.parseDouble(node.get("Volume").getTextValue());
}
}
A normal one with direct assignment work:
public Price(String companyId, LocalDate date, double closePrice, double volume) {
this.companyId = companyId;
this.date = date;
this.closePrice = closePrice;
this.volume = volume;
}
You have to make your inner classes static at the moment they require an instance of the enclosing class MongoDBConverters to be available before the object can be constructed. Making this class static doesn't require that.
public class MongoDBConverters {
public static class DateToLocalDateConverter implements Converter<Date, LocalDate> {
#Override
public LocalDate convert(Date source) {
return source == null ? null : LocalDate.fromDateFields(source);
}
}
public static class LocalDateToDateConverter implements Converter<LocalDate, Date> {
#Override
public Date convert(LocalDate source) {
return source == null ? null : source.toDate();
}
}
}
For more info check Java inner class and static nested class.

Resources