Null pointer for field injection - spring

I'm missing fundamental things here that I do, I'm sorry for this question, basically I tried to simulate my own question from Autowring for #Sevice field failed , but in very simple form , I tried to somehow raise errors on purpose for building understanding, but when it comes, I just can't handle it.
x-servlet.xml
<beans xmlns= ...... >
<context:component-scan base-package="com" />
<context:annotation-config />
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
</beans>
com.domain
Boss.java
package com.domain;
public class Boss {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Employee:
package com.domain;
import org.springframework.beans.factory.annotation.Autowired;
public class Employee {
#Autowired
private Boss boss;
String nameBoss;
public String getNameBoss() {
nameBoss = this.boss.getName();
return nameBoss;
}
}
com.controller
controller.java :
package com.controller
import com.domain.Boss;
import com.domain.Employee;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
#Controller
public class controller {
#RequestMapping("/try")
public String show() {
Boss b = new Boss();
b.setName(" hans");
Employee e = new Employee();
String bossName = e.getNameBoss();
System.out.println(bossName );
return "";
}
}
I was thinking that,
String bossName = e.getNameBoss();
in controller won't be null because Boss is already initialized right before Employee construction, but I'm wrong ..

Are you sure you want to have dependency injection (DI) for domain objects? This is not a typicall usage... For a DI, container have to create instances - so do not use new operator...
You can replace new operator using ApplicationContext.getBean() (iff the bean is of type prototype), but as I said above - even if you know how to create such beans, how should Spring know, which instance of Boss you want to have in Employee?
First thing you need is application context in controller, which should work to add interface org.springframework.context.ApplicationContextAware or you can simply autowire it and then use it "standard" way (ac is ApplicationContext):
Boss b = ac.getBean(Boss.class);
Employee e = ac.getBean(Employee.class, b);
I have Boss and Employee marked with annotations as:
#Component
#Scope("prototype")
public class Boss {
...
}
#Component
#Scope("prototype")
public class Employee {
// #Autowire - wrong
Boss boss;
public Employee(Boss boss) {
this.boss = boss;
}
...
}

Related

Spring Advice On Setter Not Triggered

i have this below code .
advice on setter is not triggered even though setter is called.
i can see it in the console
if i do advice on String getName() everything works just fine.
but its not working on setter public void setName(String name).
spring.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<aop:aspectj-autoproxy />
<bean id="cust" class="aspectJ.Customer">
<property name="name" value="logging" />
</bean>
<bean id="aspect" class="aspectJ.LoggingAspect"/>
</beans>
Logging ASPECT
#Aspect
public class LoggingAspect {
#Before("allgetters()")
public void printAspect() {
System.out.println("Aspect Running");
}
#Before("allgetters()")
public void printAspectTwo() {
System.out.println("Aspect TWO Running");
}
#Pointcut("execution(public void setName(*))")
public void allgetters() {
}
}
CUSTOMER CLASS
package aspectJ;
public class Customer {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
System.out.println("SETTER CALLED");
}
}
Main Class
public class MainClass {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
Customer obj = (Customer) context.getBean("cust");
}
}
Your aspect signature is wrong.
* will match a singular field
.. will match zero or multiple fields
Example 1
com.stackoverflow.*.Customer.setName(..)
Matches all packages starting with com.stackoverflow and ending with Customer. The wildcard will only match one package name. The method can accept zero or more arguments. Below are three examples of what it will match:
com.stackoverflow.question.Customer.setName()
com.stackoverflow.question.Customer.setName(String arg1)
com.stackoverflow.question.Customer.setName(String arg1, String arg2)
Example 2
com..Customer.setName(*, *)
Match all packages starting with com and ending with Customer. Accept methods with two arguments of any type. Below are two examples of what it will match. Notice that the wildcard will accept any number of packages.
com.example.Customer.setName(String arg1, Object arg2)
com.stackoverflow.question.Customer.setName(Integer arg1, Double arg2)
You should change your allgetters() to the following:
#Pointcut("execution(public void setName(..))")
public void allgetters() {
}
Spring AOP only works with beans managed by Spring. A bean is not managed until it is initialized, regardless if it is defined in Java or XML.
//The Customer object returned by this method is managed.
//The Customer object within the method is not managed
#Bean
public Customer createCustomer(){
//This is a pure Java object
Customer customer = new Customer();
//The object is not yet managed. This method call will therefore never be intercepted by your Pointcut.
customer.setName(“John Doe”);
return customer;
}
Quote from the documentation:
Spring AOP only supports method execution join points for Spring
beans, so you can think of a pointcut as matching the execution of
methods on Spring beans.
Just Posting what user #javamusings said :
The advice is called only when the setter is called in the Java class. It is not called when the property is initialized in the aspectj.xml

How to choose spring configuration in runtime based on a tenant?

I would like to be able to choose specific Spring (or Grails) context configuration based on the tenant that user belongs to in runtime. Let's say I use Spring Security and I retrieve tenantId during login.
Imagine now I have a two tenants and they pay different commission. How to inject specific service into a controller without too much plumbing? Here are two different contexts. So, I should inject different ExchangeService based on tenant.
#Configuration
public class FooTenant{
#Bean
public ExchangeService bar() {
return new ZeroCommisionExchangeService ();
}
}
#Configuration
public class BarTenant{
#Bean
public ExchangeService bar() {
return new StandardCommisionExchangeService ();
}
}
Edit:
I am aware I can obtain reference to Spring context and ask for service "manually", but I am looking for a more generic solution where this problematic is solved by IoC framework.
A couple of years ago we needed somthing like this but only for DataSources and ViewResolvers. We developed a solution using spring' TargetSource solution. (Initially we used a HotswappableTargetSource but that wasn't adequate for our use-case.
The code we developed is availabe here in the multi-tenant directory.
It is fully configurable and flexible.
Basically what you do is you configura a ContextSwappableTargetSource and tell it what type of interface/class it needs to return.
<bean id="yourTentantBasedServiceId" class="biz.deinum.multitenant.aop.target.ContextSwappableTargetSource">
<constructor-arg value="ExchangeService" />
</bean>
The default is to lookup beans in the ApplicationContext based on the tenantId (see the BeanFactoryTargetRegistry for this). However you can specify one or more of those (we used a JndiLookupTargetRegistry to dynamically lookup datasource, which allowed use to add tenants on the fly without restarting the application).
If you explicitly configure a BeanFactoryTargetRegistry you can add a prefix and suffix.
<bean id="exchangeService" class="biz.deinum.multitenant.aop.target.ContextSwappableTargetSource">
<constructor-arg value="ExchangeService" />
<property name="targetRegistry>
<bean class="biz.deinum.multitenant.aop.target.registry.impl.BeanFactoryTargetRegistry">
<property suffix="ExchangeService"/>
</bean>
</property>
</bean>
Now for foo it would lookup a bean named fooExchangeService and for bar barExchangeService.
The tenantId is stored in a ThreadLocal which is wrapped inside the ContextHolder. You need to find a way to fill and clear this thread local (in general a servlet Filter does that trick.
In your code you can now simply use the interface ExchangeService and at runtime based on the tenantId the correct implemenation will be looked up.
Also see http://mdeinum.wordpress.com/2007/01/05/one-application-per-client-database/
Assuming you have different services already defined, you can get their bean from the context and use it. In my example, all the services have implementation of serviceMethod and based on some criteria pick your proper service. The only thing I am not sure is how Multitenancy might impact this.
import org.springframework.context.ApplicationContext
class ServiceManagerController {
def serviceManager
def index() {
ApplicationContext ctx = grails.util.Holders.grailsApplication.mainContext
serviceManager = ctx.getBean(params.serviceName); //firstService or secondService
render serviceManager.serviceMethod()
}
}
FirstService
class FirstService {
def serviceMethod() {
return "first"
}
}
SecondService:
class SecondService {
def serviceMethod() {
return "second"
}
}
While it is possible to swap beans instantiated in a spring context at runtime (HotswappableTargetSource), it is not meant for use cases such as yours.
Remember there is one Spring Context for your application, all threads use the same instances (in most cases), this implies when you swap out a bean implementation, you are affectively doing this for all your application's users. To prevent this, you run into issues of ensuring Thread Safety, employing Thread Locals, as listed in another answer.
While it is possible to continue this approach and arrive at an implementation that gets the job done, it would definitely be a very contrived way of solving this problem.
You should take a step back and look at your problem in a more wholesome, system wide design point of view. Bust out your patterns books and look at how this can be resolved, regardless of whether you use Spring or an other framework. Service Locator, Factory bean etc described in some of the answers above is a step in the correct direction.
Your Use Case is pretty common for multi-tenant applications. You need to narrow down things that are likely to change based on a tenantId versus things that are constant across.
For instance as mentioned in the question, each Tenant might have a different commission amount or even different algorithm for commission calculation. A simple solution to this would be to implement a CommissionCalculationService which accepts a tenantId, and any other domain object based on which commission is to be calculated, I would imagine this would be something like Order or Sale, whatever makes sense in your application.
You now need a CommissionServiceFactory or a ServiceLocator which will contain tenant specific implementations of the CommissionCalculationService. The Service Locator is instantiated when the Spring context loads, and is injected with implementation classes also at application startup.
When you want to calculate commission for a tenant, you basically obtain the tenantId from the user's login, pass the tenant id to your service locator, based on the tenantId passed, the service locator returns the appropriate instance of a Service Implementation. In your calling class, use this instance to calculate the commission for the tenant.
Another pattern to consider is the Strategy Pattern, or even Template Pattern.
Bottom line, even if you want tenant specific logic implemented cleanly, don't thing about changing the beans loaded in the context. Have classes in your context that can handle all your tenant specific logic. Rely on design patterns to use the correct bean from the context based on the tenant id.
I apologize if the answer was a little verbose, I felt it was needed to explain why I think updating beans in a loaded Spring Context is not the appropriate solution.
I use the following code:
public class ConfigurableProxyFactoryBean implements FactoryBean<Object>, BeanNameAware {
#Autowired
private ApplicationContextProvider applicationContextProvider;
private Class<?> proxyType;
private String beanName;
private Object object;
private Object fallbackObject;
private Object monitor = new Object();
private ConfigurableProxy proxy;
public ConfigurableProxyFactoryBean(Class<?> proxyType) {
this.proxyType = proxyType;
}
public Object getFallbackObject() {
return fallbackObject;
}
public void setFallbackObject(Object fallbackObject) {
synchronized (monitor) {
this.fallbackObject = fallbackObject;
if (proxy != null) {
proxy.setFallbackObject(fallbackObject);
}
}
}
#Override
public void setBeanName(String name) {
beanName = name;
}
#Override
public Object getObject() throws Exception {
synchronized (monitor) {
if (object == null) {
#SuppressWarnings("unchecked")
Class<Object> type = (Class<Object>)proxyType;
proxy = new ConfigurableProxy(applicationContextProvider, beanName);
proxy.setFallbackObject(fallbackObject);
object = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
new Class<?>[] { type }, proxy);
}
return object;
}
}
#Override
public Class<?> getObjectType() {
return proxyType;
}
#Override
public boolean isSingleton() {
return true;
}
}
class ConfigurableProxy implements InvocationHandler {
public ConfigurableProxy(ApplicationContextProvider appContextProvider, String beanName) {
this.appContextProvider = appContextProvider;
this.beanName = beanName;
}
private ApplicationContextProvider appContextProvider;
private String beanName;
private Object fallbackObject;
#Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
ApplicationContext appContext = appContextProvider.getApplicationContext();
String name = "$&&#" + beanName;
Object bean = appContext.containsBean(name) ? appContext.getBean(name) : fallbackObject;
return method.invoke(bean, args);
}
public void setFallbackObject(Object fallbackObject) {
this.fallbackObject = fallbackObject;
}
}
ApplicationContextProvider has implementation, that chooses ApplicationContext according to current tennant.
In XML configuration it is used like this:
<bean class="my.package.infrastructure.ConfigurableProxyFactoryBean" name="beanName">
<constructor-arg>
<value type="java.lang.Class">my.package.model.ServiceInterface</value>
</constructor-arg>
<property name="fallbackObject">
<bean class="my.package.service.DefaultServiceImplementation"/>
</property>
</bean>
And in tennant configuration that way:
<bean class="my.package.service.ServiceImplementationA" name="$&&#beanName"/>
To inject this service somewhere you just write:
public class MyController {
#Autowired
private ServiceInterface service;
}
Also you are to implement ApplicationContextProvider, I won't share mine. It is not very hard to implement. For example, your implementation can just store context in ThreadLocal. And you create your own ServletContextListener, which for every query gets the current tennant and stores it into your ApplicationContextProvider implementation.
The new tenant scope and a servicelocator can helps
Tenant scope will guarantee than service is created one time for a tenant
Sample code:
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
<property name="scopes">
<map>
<entry key="tenant" value="foo.TenantScope"/>
</map>
</property>
</bean>
<bean id="service" class="foo.Service" factory-bean="tenantServiceLocator" factory-method="createInstance" scope="tenant"/>
<bean id="fooService" class="FooService">
<bean id="barService" class="BarService">
<bean id="tenantServiceLocator" class="foo.TenantServiceLocator">
<property name="services">
<map>
<entry key="foo" value-ref="fooService"/>
<entry key="bar" value-ref="barService"/>
</map>
</property>
</bean>
TenantServiceLocator should know the user tenantId
public class TenantServiceLocator {
private Map<String, Service> services;
public String getTenantId() {
return "foo"; // get it from user in session
}
public Map<String, Service> getServices() {
return services;
}
public void setServices(Map<String, Service> services) {
this.services = services;
}
public Service createInstance(){
return services.get(tenantId);
}
}
public class FooController{
#Autowired
private Service service;
}
A sample TenantScope implementation
public class TenantScope implements Scope {
private static Map<String, Map<String, Object>> scopeMap = new HashMap<String, Map<String, Object>>();
#Override
public Object get(String name, ObjectFactory<?> objectFactory) {
Map<String, Object> scope = getTenantScope(getTenantId());
Object object = scope.get(name);
if(object == null){
object = objectFactory.getObject();
scope.put(name, object);
}
return object;
}
private Map<String, Object> getTenantScope(String tenantId) {
if (!scopeMap.containsKey(tenantId)) {
scopeMap.put(tenantId, new HashMap<String, Object>());
}
return scopeMap.get(tenantId);
}
private String getTenantId() {
return "foo"; // load you tenantId
}
#Override
public Object remove(String name) {
Map<String, Object> scope = getTenantScope(getTenantId());
return scope.remove(name);
}
#Override
public void registerDestructionCallback(String name, Runnable callback) {
}
#Override
public Object resolveContextualObject(String key) {
return null;
}
#Override
public String getConversationId() {
return null;
}
}
Transforming my comment in an answer, one possible solution is to create a spring factory bean, that receive all he needs to decide which service needs to be returned when creating the instance.
Translating to Grails:
public interface ChoosableServiceIntf {
String getName();
}
class NormalService implements ChoosableServiceIntf {
public String getName() {
return getClass().name;
}
}
class ExtendedService implements ChoosableServiceIntf {
public String getName() {
return getClass().name
}
}
class ChoosableServiceFactory {
static ChoosableServiceIntf getInstance(String decisionParam) {
if(decisionParam == 'X') {
return applicationContext.getBean('extendedService')
}
return applicationContext.getBean('normalService')
}
static ApplicationContext getApplicationContext() {
return Holders.grailsApplication.mainContext
}
}
Here we have two services and ChoosableServiceFactory is responsible to know witch is the correct one.
Then you will need to use the method ApplicationContext#getBean(String, Object[]) to return the correct instance and will also make the factory prototyped scope because of the runtime params.
A controller to test it:
class MyController {
def grailsApplication
def index() {
ChoosableServiceIntf service = grailsApplication.mainContext.getBean('choosableServiceFactory', ["X"] as Object[])
ChoosableServiceIntf serviceNormal = grailsApplication.mainContext.getBean('choosableServiceFactory', ["N"] as Object[])
render text: "#1 - ${service.class.name} , #2 - ${serviceNormal.class.name}"
}
}
This will print #1 - dummy.ExtendedService , #2 - dummy.NormalService
The declaration of the beans will be:
choosableServiceFactory(ChoosableServiceFactory) { bean ->
bean.scope = 'prototype'
bean.factoryMethod = 'getInstance'
}
normalService(NormalService)
extendedService(ExtendedService)

Spring Data Solr multiple cores and repository

I have apache solr with multiple cores e.g. currency, country etc... So using Spring Data Solr I can retrieve information from one core. I have got this XML configuration right now queries against 'currency' core. If I wanted to query against 'country' core how can I set this up?
<!-- Enable Solr repositories and configure repository base package -->
<solr:repositories base-package="com.acme.repository" solr-template-ref="solrCurrencyTemplate"/>
<solr:solr-server id="solrCurrencyServer" url="http://localhost:8983/solr/currency"/>
<bean id="solrCurrencyTemplate" class="org.springframework.data.solr.core.SolrTemplate">
<constructor-arg ref="solrCurrencyServer" />
</bean>
and have the repository defined as
#Repository
public interface CurrencyRepository extends SolrCrudRepository<Currency, String> {
}
and from my service I can do this
#Override
public List<Currency> getCurrencies() {
Page<Currency> currencies = (Page<Currency>) currencyRepository.findAll();
return currencies.getContent();
}
I have also tried using #SolrDocument(solrCoreName = "currency") but this din't work.
#SolrDocument(solrCoreName = "currency")
public class Currency {
public static final String FIELD_CURRENCY_NAME = "currency_name";
public static final String FIELD_CURRENCY_CODE = "currency_code";
public static final String FIELD_DECIMALS = "decimals";
#Id
#Field(value = FIELD_CURRENCY_CODE)
private String currencyCode;
//currency_name,decimals
#Field(value = FIELD_CURRENCY_NAME)
private String currencyName;
#Field(value = FIELD_DECIMALS)
private String decimals;
...
...
...
}
I need help on this asap... otherwise I will have to go back to the RestTemplate Solution :-(
Hope someone can help.
Thanks
GM
Thought I would share, We spend lot of time recently configuring multiple cores. We did in java, not xml.
As part of spring #configuration add following.
#Bean(name="solrCore1Template")
public SolrTemplate solrCore1Template() throws Exception {
EmbeddedSolrServer embeddedSolrServer = new EmbeddedSolrServer(getCoreContainer(), "core1");
return new SolrTemplate(embeddedSolrServer);
}
#Bean(name="solrCore2Template")
public SolrTemplate solrCore2Template() throws Exception {
EmbeddedSolrServer embeddedSolrServer = new EmbeddedSolrServer(getCoreContainer(), "core2");
return new SolrTemplate(embeddedSolrServer);
}
#Bean
#Scope
public CoreContainer getCoreContainer() throws FileNotFoundException{
String dir = <path_to_solr_home>;
System.setProperty("solr.solr.home", dir);
CoreContainer.Initializer initializer = new CoreContainer.Initializer();
return initializer.initialize();
}
And to use each template use like below in service classes.
#Resource
private SolrTemplate solrCore1Template;
Embedded server can be relaced with HTTP using below code.
HttpSolrServer httpSolrServer = new HttpSolrServer(getSolrURL());
return new SolrTemplate(httpSolrServer, "core1");
Hope this helps. I know it's a very late reply for the question asked.
multicore support via namespace config is unfortunately an open issue. You'll need to have a separate SolrTemplate for each core and create repositories manually.
#Autowired
#Qualifier("solrCurrencyTemplate")
private SolrTemplate solrCurrencyTemplate;
#Autowired
#Qualifier("solrCountryTemplate")
private SolrTemplate solrCountryTemplate;
//...
CurrencyRepository currencyRepo = new SolrRepositoryFactory(this.solrCurrencyTemplate)
.getRepository(CurrencyRepository.class);
CountryRepository countryRepo = new SolrRepositoryFactory(this.solrCountryTemplate)
.getRepository(CountryRepository.class);
Spring Data now supports multiple cores with their respective repositories.
The multicoreSupport flag needs to be true in #EnableSolrRepositories annotation and the corresponding document needs to be told what core they belong to. Like:
#SolrDocument(solrCoreName = "currency")
public class Currency
{
// attributes
}
the other class should be
#SolrDocument(solrCoreName = "country")
public class Country
{
// attributes
}
The respective repositories should know what pojo they are working with.
public interface CurrencyRepository extends SolrCrudRepository<Currency,String>
{
}
and
public interface CountryRepository extends SolrCrudRepository<Country,String>
{
}
and configuration should be
#Configuration
#EnableSolrRepositories(value = "com.package.name",multicoreSupport = true)
public class SolrConfig
{
#Bean
public SolrServer solrServer() throws Exception
{
HttpSolrServerFactoryBean f = new HttpSolrServerFactoryBean();
f.setUrl("http://localhost:8983/solr");
f.afterPropertiesSet();
return f.getSolrServer();
}
#Bean
public SolrTemplate solrTemplate(SolrServer solrServer) throws Exception
{
return new SolrTemplate(solrServer());
}
}
With Spring Data Solr 1.1.0.RC1 multiple cores works as described by Christoph Strobl with #EnableSolrRepositories. It works also with an XML configuration by set multicore-support="true".
<solr:repositories base-package="your.solr.repo.package" repository-impl-postfix="Impl" multicore-support="true"/>
<solr:solr-server id="solrServer" url="${solr.server.base.connection.url}" />
<bean id="solrTemplate" class="org.springframework.data.solr.core.SolrTemplate">
<constructor-arg index="0" ref="solrServer" />
</bean>
<solr:solr-server id="solrServer" timeout="1000" maxConnections="1000" url="${solr.server.1},${solr.server.2}"/>
<bean id="solrServerFactory" class="org.springframework.data.solr.server.support.MulticoreSolrServerFactory">
<constructor-arg ref="solrServer" />
<constructor-arg name="cores">
<list>
<value>${solr.index.customer}</value>
<value>${solr.index.task}</value>
</list>
</constructor-arg>
</bean>
<bean id="solrTemplate" class="org.springframework.data.solr.core.SolrTemplate">
<constructor-arg ref="solrServerFactory" />
</bean>
<solr:repositories base-package="com.deve.pig.solr" multicore-support="true" solr-template-ref="solrTemplate" />

Bean property 'xxx' is not writable or has an invalid setter method

I have spring web application. I have defined the controller bean which takes the bean of service as property. Also service bean takes the Dao. Dao is tested and working fine. Now the problem with service. Actually i'd make sure about the setters there !
so what is the problem ?
Controller Bean :
<bean id="listTypeController" class="me.web.servlet.controller.ListTypeController">
<property name="typeService" ref="typeService" />
</bean>
Service Bean :
<bean id="typeService"class="me.general.service.impl.TypeServiceImpl">
<property name="genericDao" ref="genericDao" />
<property name="typeDao" ref="typeDao" />
</bean>
Service class:
public class TypeServiceImpl implements TypeService {
private TypeDao typeDao;
private GenericDao genericDao;
public TypeDao getTypeDao() {
return typeDao;
}
public GenericDao getGenericDao() {
return genericDao;
}
public void setTypeDao(TypeDao typeDao) {
this.typeDao = typeDao;
}
public void setGenericDao(GenericDao genericDao) {
this.genericDao = genericDao;
}
}
List Controller:
public class ListTypeController {
public static final String SEARCH_TYPE_FORM_ATTRIBUTE_NAME = "SearchTypeForm";
private TypeService typeService;
#ModelAttributeSEARCH_TYPE_FORM_ATTRIBUTE_NAME)
public SearchTypeForm createForm() {
SearchTypeForm form = new SearchTypeForm();
form.setPageSize(SystemConfiguration.getCurrentConfiguration().getDefaultPageSize());
form.setActive(Boolean.TRUE);
return form;
}
#RequestMapping("/administration/types")
public String listTypes(#ModelAttribute(SEARCH_TYPE_FORM_ATTRIBUTE_NAME) SearchTypeForm form,
Model model) {
Page<Type> all = typeService.findTypes(form);
model.addAttribute("all", all);
return "/master/general/List";
}
public void setTypeServic(TypeService typeService) {
this.typeService = typeService;
}
}
The Error :
Invalid property 'typeService' of bean class
[me.web.servlet.controller.ListTypeController]:
Bean property 'typeService' is not writable or has an invalid setter method.
Does the parameter type of the setter match the return type of the getter?
ListTypeController doesn't have a property of the appropriate type to receive the typeService bean, or else the setter for that property is malformed. Note that if you have some proxying going on and your ListTypeController specifies the type as TypeServiceImpl, then it may be because you should be referring to the bean by its interface type, TypeService. A proxy of your typeService would be a TypeService, but not a TypeServiceImpl.
Update: Based on your new code: setTypeServic should be setTypeService, or else your property name is actually typeServic.
In my case i named my propery as: isMyProperty and is in prefix caused an issue. I had to change the name to myProperty.
In my case it was because I had correct setter and getter but each with different type.
My setter took String and parsed it to target enum type and my getter returned directly the enum.
For some reason Spring (v3) got confused.

Dozer custom converter ID mapping: Object to Long and Long to Object via DozerConverter getParameter

I need help configuring my dozer mapping file.
Mainly I would like to know how to get User user obejct to convert to Long userId.
Hence map: user >> userId
But I have multiple objects such as comment >> commentId or address >> addressId
therefor I'd like to have something more elegant than just writing mapping for each of the fields. All of the object implement Loadable interface.
The bellow code is now functioning thanks to the getParameter() DozerConverter method, but if you know any better way than the converter that I wrote please let me know.
// dozer.xml
<?xml version="1.0" encoding="UTF-8"?>
<mappings xmlns="http://dozer.sourceforge.net"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://dozer.sourceforge.net http://dozer.sourceforge.net/schema/beanmapping.xsd">
<configuration>
<custom-converters>
<converter type="project.shared.domain.dto.dozer.LoadableIdConverter" >
<class-a>project.shared.domain.Loadable</class-a>
<class-b>java.lang.Long</class-b>
</converter>
</custom-converters>
</configuration>
<mapping>
<class-a>project.shared.domain.Suggestion</class-a>
<class-b>project.shared.domain.dto.DTOSuggestion</class-b>
<field custom-converter-param="User">
<a>user</a>
<b>userId</b>
</field>
</mapping>
</mappings>\
// Spring Application context
<bean id="loadableIdConverter" class="project.shared.domain.dto.dozer.LoadableIdConverter">
<property name="userService" ref="userService"/>
<property name="commentService" ref="commentService"/>
<property name="addressService" ref="addressService"/>
</bean>
<bean id="gwtMapper" class="org.dozer.DozerBeanMapper">
<property name="mappingFiles">
<list>
<value>classpath:/dozer.xml</value>
</list>
</property>
<property name="customConverters">
<list>
<ref bean="loadableIdConverter"/>
</list>
</property>
</bean>
//Standard hibernate object
public class Suggestion implements Serializable, Loadable {
private long id = -1;
private Date dateCreated;
private User user; //trying to use dozer to covert this bad boy to Long userId
//...
}
//DTO object
public class DTOSuggestion implements IsSerializable {
private long id = -1;
private Date dateCreated;
private Long userId; //trying to get this ID via the dozer converter
//...
}
//Loadable interface
public interface Loadable extends Serializable {
public long getId();
public void setId(long id);
}
//Dozer converter
public class LoadableIdConverter extends DozerConverter<Loadable, Long> {
private UserService userService; //configured in applicationcontext
private AddressService addressService; //configured in applicationcontext
private CommentService commentService; //configured in applicationcontext
public LoadableIdConverter() {
super(Loadable.class, Long.class);
}
public Long convertTo(Loadable object, Long id) {
return object.getId();
}
public Loadable convertFrom(Long id, Loadable object) {
if (id < 0) return null;
String loadable = getParameter();
if (loadable.equalsIgnoreCase("User"))
return userService.get(User.class, id);
if (loadable.equalsIgnoreCase("Address"))
return addressService.get(Address.class, id);
if (loadable.equalsIgnoreCase("Comment"))
return commentService.get(Comment.class, id);
return null;
}
}
There is one trick you could use to avoid converter parameters. If you fall back to older custom converter approach in Dozer, which is implementing CustomConverter interface, you will get two additional parameters: existingDestinationValue and destinationClass.
convert(Object existingDestinationFieldValue, Object sourceFieldValue, Class<?> destinationClass, Class<?> sourceClass)
By using these values you could introspect your destination field via reflection and know what is the expected concrete implementation of Loadable interface. This works only if you define the field types with concrete types of course. But you already have it in your example, so this should not be a problem. CustomConverter implementation will be more verbose as you need to determine the direction of the mapping manually, but it gives you full control of what is going on during the mapping process.

Resources