I am new to Spring. I am trying implementing CustomPropertyEditor using PropertyEditorSupport and registering the CustomPropertyEditor in app-context.xml.
Please find the code below.
public class NamePropertyEditor extends PropertyEditorSupport{
#Override
public void setAsText(String text) throws IllegalArgumentException {
//String[] name = text.split(":");
System.out.println("text: "+ text);
Name result = new Name(text, "randomString");
setValue(result);
}
}
app-context file
<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="customEditors">
<map>
<entry key="com.property.bean.Name">
<bean class="com.property.editor.NamePropertyEditor"/>
</entry>
</map>
</property>
</bean>
<bean id="exampleBean" class="com.start.CustomEditorExample">
<property name="name">
<value>Varun Bhatia</value></property>
</bean>
Class trying to use PropertyEditor
public static void main(String[] args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:/META-INF/spring/app-context.xml");
//ctx.refresh();
CustomEditorExample bean = (CustomEditorExample) ctx.getBean("exampleBean");
System.out.println(bean.getName());
}
public Name getName() {
System.out.println("getName");
return name;
}
public void setName(Name name) {
System.out.println("setName");
this.name = name;
}
Problem is control is not going to setAsText method.
Code that you have written in main() will not invoke your property editor
Try something like
CustomEditorExample bean = (CustomEditorExample) ctx.getBean("exampleBean");
BeanWrapper wrapper = new BeanWrapperImpl(bean );
wrapper.setPropertyValue("name", "Some Text");//this will invoke your property editor
System.out.println(bean.getName());
I would advise you to read this Spring Docs
Related
I have a custom writer with a FlatFileItemWriter and i want to pass a job parameter( a output file) defined in the main class
How can i deal with this ?
Thank you very much
CustomWriter
public class PersonItemWriter implements ItemWriter<Person> {
private FlatFileItemWriter<String> flatFileItemWriter = new FlatFileItemWriter<String>();
private Resource resource;
#Override
public void write(List<? extends Person> personList) throws Exception {
flatFileItemWriter.setResource(new FileSystemResource(resource.getFile()));
PassThroughLineAggregator<String> aggregator = new PassThroughLineAggregator<String();
flatFileItemWriter.setLineAggregator(aggregator);
flatFileItemWriter.open(new ExecutionContext());
flatFileItemWriter.write(Arrays.asList(aggregator.aggregate("test")));
flatFileItemWriter.close();
}
public void setResource(Resource resource) {
this.resource = resource;
}
}
Launcher
JobLauncher jobLauncher = (JobLauncher) applicationContext.getBean("jobLauncher");
Job job = (Job) applicationContext.getBean("personJob");
/* Parameters sent to job */
JobParametersBuilder jobParametersBuilder = new JobParametersBuilder();
jobParametersBuilder.addString("outputFileName", "file:" + personFile); // pass this to the itemWriter
configuration job xml
<bean id="personWriter" class="com.dev.writer.PersonItemWriter" scope="step>
<property name="resource" value="#{jobParameters[outputFileName]}" />
</bean>
You have to declare the bean with either step scope or job scope so you can have late binding of a property based on the job parameter:
<bean id="personWriter" class="com.dev.writer.PersonItemWriter" scope="step">
<property name="resource" value="#{jobParameters[outputFileName]}" />
</bean>
These scopes are not available by default, you need to include them either by either using the batch namespace or defining the following bean:
<bean class="org.springframework.batch.core.scope.StepScope" />
Update:
Here's the complete writer:
public class PersonItemWriter implements ItemWriter<Person> {
FlatFileItemWriter<String> flatFileItemWriter = new FlatFileItemWriter<String>();
private Resource resource;
#Override
public void write(List<? extends Person> personList) throws Exception {
flatFileItemWriter.setResource(resource);// how the pass the job parameter file here
PassThroughLineAggregator<String> aggregator = new PassThroughLineAggregator<String();
flatFileItemWriter.setLineAggregator(aggregator);
aggregator.aggregate("test"); // do not save in output file
}
public FlatFileItemWriter<String> getFlatFileItemWriter() {
return flatFileItemWriter;
}
public void setFlatFileItemWriter(FlatFileItemWriter<String> flatFileItemWriter) {
this.flatFileItemWriter = flatFileItemWriter;
}
public void setResource(Resource resource) {
this.resource = resource;
}
}
You can define a HashMap and use this HashMap instead of jobParameter.
<bean id="paramBean" class="java.util.HashMap"/>
<bean id="personWriter" class="com.dev.writer.PersonItemWriter" scope="step">
<property name="resource" value="#{paramBean[outputFileName]}" />
</bean>
Write the setter method in ItemWriter and set the values in the HashMap.
private HashMap paramBean;
public void setParamBean(HashMap paramBean) {
this.paramBean= paramBean;
}
paramBean.set(<key>,<value>);
I have a Spring-ws and i am using Apahce-wss4j for spring-ws authentication. I want to use my Dao class in my custom TokenValidator class. But there was an exception can not #Autowired my Dao class. Here is my code
applicationContext.xml
<bean id="myWssConfig" class="tr.com.xxx.services.MyWssConfig"/>
<bean id="kepDBDAO" class="tr.com.xxx.dao.KepDBDAOImpl"/>
<bean id="ssha" class="tr.com.xxx.utils.SSHA"/>
<bean id="memberStatusService" class="tr.com.xxx.services.MemberStatusServiceImpl"/>
<bean id="myUsernameTokenValidator" class="tr.com.xxx.services.MyUsernameTokenValidator">
<property name="kepDBDAO" ref="kepDBDAO"/>
</bean>
<sws:interceptors>
<bean class="org.springframework.ws.soap.security.wss4j.Wss4jSecurityInterceptor">
<property name="validationActions" value="UsernameToken"/>
<property name="validationCallbackHandler" ref="callbackHandler"/>
<property name="wssConfig">
<ref bean="myWssConfig"/>
</property>
</bean>
</sws:interceptors>
Here is MyWssConfig.java
#Component("myWssConfig")
public class MyWssConfig extends WSSConfig {
public MyWssConfig() {
setValidator(WSSecurityEngine.USERNAME_TOKEN, MyUsernameTokenValidator.class);
setRequiredPasswordType(WSConstants.PASSWORD_TEXT);
}
}
And here is MyUsernameTokenValidator.java
#Component
public class MyUsernameTokenValidator extends UsernameTokenValidator {
private static final Logger LOGGER = LoggerFactory
.getLogger(MyUsernameTokenValidator.class);
#Autowired
private KepDBDAO kepDBDAO;
#Transactional
protected void verifyPlaintextPassword(UsernameToken usernameToken, RequestData data) throws WSSecurityException {
if (usernameToken != null && usernameToken.getPassword() != null) {
byte[] saltValue = null;
kepDBDAO.getWsUsers("basvuru");
String hashPassword = null;
try {
hashPassword = SSHA.calculateSSHA256(saltValue, usernameToken.getPassword());
} catch (NoSuchAlgorithmException e) {
LOGGER.error(e.toString(), e);
} catch (IOException e) {
LOGGER.error(e.toString(), e);
}
usernameToken.setPassword(hashPassword);
super.verifyDigestPassword(usernameToken, data);
}
}
public KepDBDAO getKepDBDAO() {
return kepDBDAO;
}
public void setKepDBDAO(KepDBDAO kepDBDAO) {
this.kepDBDAO = kepDBDAO;
}
}
Couldn't #Autowired my KepDBDAO when I call webservice in SOAPUI.
Help me please.. THank you all guys.
Try this:
1. In applicationContext:
<context:component-scan base-package="tr.com.xxx.dao"/>
<context:component-scan base-package="package for MyUsernameTokenValidator"/>
remove these beans:
kepDBDAO, myUsernameTokenValidator
2. Remove setter and getter for KepDBDAO in MyUsernameTokenValidator
3. Make sure KepDBDAOImpl is marked as #Service
I solved my problem.
#Component("myWssConfig")
public class MyWssConfig extends WSSConfig {
#Autowired
private MyUsernameTokenValidator myUsernameTokenValidator;
//
#PostConstruct
public void myInit() {
setValidator(WSSecurityEngine.USERNAME_TOKEN, myUsernameTokenValidator);
setRequiredPasswordType(WSConstants.PASSWORD_TEXT);
}
}
I've looked around bit but can't figure out what am I missing trying to get xml view of result.
Following is the exception I am getting:
javax.servlet.ServletException: Unable to locate object to be marshalled in model: {movies=[com.wickedlynotsmart.imdb.model.Movie#1450f1f, com.wickedlynotsmart.imdb.model.Movie#ac622a, com.wickedlynotsmart.imdb.model.Movie#160c21a, com.wickedlynotsmart.imdb.model.Movie#1677737, com.wickedlynotsmart.imdb.model.Movie#1c3dc66]}
at org.springframework.web.servlet.view.xml.MarshallingView.renderMergedOutputModel(MarshallingView.java:100)
at org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:250)
...
...
Following are the files included in handling the request:
servlet application context file
<bean id="jaxbMarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name="classesToBeBound">
<list>
<value>com.wickedlynotsmart.imdb.model.Movie</value>
</list>
</property>
</bean>
<bean id="movies" class="org.springframework.web.servlet.view.xml.MarshallingView">
<constructor-arg ref="jaxbMarshaller" />
</bean>
domain object
#Entity
#XmlRootElement
public class Movie implements Serializable {
public Movie() {}
//interesting stuff
}
controller
#RequestMapping("/movies")
public class MoviesController {
private static final Log logger = LogFactory.getLog(MoviesController.class);
#Autowired
private MovieManagementService movieManagementService;
#RequestMapping(method=RequestMethod.GET)
public String findAllMovies(Model model) {
List<Movie> movies = movieManagementService.getAllMovies();
model.addAttribute("movies", movies);
return "movies";
}
//interesting stuff
}
Could someone help me out with what I might be missing here?
Thanks.
EDIT: I am basically trying to see BeanNameViewResolver in action for which I already have BeanNameViewResolver configured in the configuration file as following:
<bean id="beanNameViewResolver" class="org.springframework.web.servlet.view.BeanNameViewResolver">
<property name="order" value="2" />
</bean>
Following changes got things working:
wrapper for Movie class to keep JAXB happy
#XmlRootElement(name="movies")
public class MovieList {
private List<Movie> movieList;
public MovieList() {}
public MovieList(List<Movie> movieList) {
this.movieList = movieList;
}
#XmlElement(name="movie")
public List<Movie> getMovieList() {
return movieList;
}
public void setMovieList(List<Movie> movieList) {
this.movieList = movieList;
}
}
controller
#RequestMapping(method=RequestMethod.GET)
public String findAllMovies(Model model) throws MovieNotFoundException {
List<Movie> movieList = movieManagementService.getAllMovies();
MovieList movies = new MovieList(movieList);
model.addAttribute("movies", movies);
return "movies";
}
sevlet application context
<bean id="jaxbMarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name="classesToBeBound">
<list>
<value>com.wickedlynotsmart.imdb.model.Movie</value>
<value>com.wickedlynotsmart.imdb.model.MovieList</value>
</list>
</property>
</bean>
Why use AbstractRoutingDataSource can not dynamic switch DataSource
This is the configuration information
public class DynamicSwitch {
public static final ThreadLocal<String> local=new ThreadLocal<String>();
public static void setDB(String id){
local.set(id);
}
public static String getDB(){
return local.get();
}
public static void removeDB(){
local.remove();
}
}
public class DynamicSource extends AbstractRoutingDataSource implements InitializingBean{
#Override
protected Object determineCurrentLookupKey() {
// TODO Auto-generated method stub
return DynamicSwitch.getDB();
}
}
<bean id="dynamic" class="com.aware.DynamicSource">
<property name="targetDataSources">
<map key-type="java.lang.String">
<entry key="1" value-ref="dataSource"></entry>
<entry key="2" value-ref="localdataSource"></entry>
</map>
</property>
<property name="defaultTargetDataSource" ref="dataSource"></property>
</bean>
<bean id="methodService" class="com.test.service.MethodServiceImpl">
<property name="sqlMapClient" ref="sqlMapClient"></property>
</bean>
<bean id="test" class="com.test.Test" scope="prototype"></bean>
public class Test2 extends ActionSupport{
public String execute() throws Exception {
// TODO Auto-generated method stub
DynamicSwitch.setDB("2");
MethodService methodService=(MethodService)ApplicationAware.getBean("methodService");
Map<String, String> map=new HashMap<String, String>();
List list=methodService.testList("Service_ks_missionSpace.getService_ks_missionList", map);
System.out.println(list.size());
return SUCCESS;
}
Invoke DynamicSwitch.setDB("2") find can not Switch DataSource.
DataSource or to default dataSource
Why
Is there a way in Spring to create a collection, or array, of beans, based on a comma-separated list of classes. For example:
package mypackage;
public class Bla {
private Set<MyBean> beans;
public void setBeans(Set<MyBean> beans) {
this.beans = beans;
}
}
With the application context:
<bean id="bla" class="mypackage.Bla">
<property name="beans">
<set>
<bean class="mypackage.Bean1, mypackage.Bean2" />
</set>
</property>
</bean>
Preferably the beans are all initialized and wired from the context, leaving the code as simplistic as possible, is this possible?
Use a combination of ApplicationContextAware and ApplicationListener:
public class BeanInitializer implements ApplicationContextAware, ApplicationListener<ContextRefreshedEvent> {
private ApplicationContext context;
private List<Class<?>> beanClasses;
public void onApplicationEvent(final ContextRefreshedEvent event) {
final AutowireCapableBeanFactory beanFactory = this.context.getAutowireCapableBeanFactory();
for (final Class<?> beanClass : this.beanClasses) {
beanFactory.autowire(beanClass, AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, true);
}
}
public void setApplicationContext(final ApplicationContext context) throws BeansException {
this.context = context;
}
public void setBeanClasses(final List<Class<?>> beanClasses) {
this.beanClasses = beanClasses;
}
}
in your spring config, do this:
<bean class="com.yourcompany.BeanInitializer">
<property name="beanClasses">
<list>
<value>com.yourcompany.Type1</value>
<value>com.yourcompany.Type2</value>
<value>com.yourcompany.Type3</value>
</list>
</property>
</bean>
Edited: Actually, if you want comma separated, it will probably be more like this:
<bean class="com.yourcompany.BeanInitializer">
<property name="beanClasses"
value="com.yourcompany.Type1,com.yourcompany.Type2,com.yourcompany.Type3" />
</bean>
I don't know if there is a built-in property editor that converts a comma delimited string to a list of classes but if not you can either create one yourself or change your setter method to accept a string and parse the string yourself