4

i am trying to config dozer in spring configuration. when using xml config it would be like

<bean class="org.dozer.spring.DozerBeanMapperFactoryBean">
    <property name="mappingFiles" value="classpath*:dozer/**/*.dzr.xml"/>
</bean>

how can i define resources in config file. i tried using ctx.getResource() but i cannot access to ApplicationContext in Configuration class.

i tried ContextRefreshedEvent and add resources from there, but still no luck. (afterPropertiesSet is already called and added mappings wont work)

public class ContextRefreshedEventBuilder extends ContextRefreshedEvent {
public ContextRefreshedEventBuilder(ApplicationContext ctx) {
    super(ctx);
    DozerBeanMapperFactoryBean mapper = ctx.getBean(DozerBeanMapperFactoryBean.class);
    try {
        mapper.setMappingFiles(ctx.getResources("classpath*:dozer/**/*.dzr.xml"));
    } catch (IOException e) {
        e.printStackTrace();
    }
}
}

also tried to use ClassPathResource but can't find the correct way to

DozerBeanMapperFactoryBean mapper = new DozerBeanMapperFactoryBean();
mapper.setMappingFiles(new Resource[]{new ClassPathResource("classpath*:dozer/**/*.dzr.xml")});
return mapper;

how can i add ClassPathResource as mapping locations?

---ANSWER---

@Bean
public DozerBeanMapperFactoryBean configDozer() throws IOException {
    DozerBeanMapperFactoryBean mapper = new DozerBeanMapperFactoryBean();
    Resource[] resources = new PathMatchingResourcePatternResolver().getResources("classpath*:dozer/**/*.dzr.xml");
    mapper.setMappingFiles(resources);
    return mapper;
}
alizelzele
  • 892
  • 2
  • 19
  • 34
  • Inject the `ResourceLoader` or `ApplicationContext`. Construct a `PathMatchingResourcePatternResolver` with it (you could also try to create on without the context or resource loader) and use the `getResources` method with your pattern to get the resources. – M. Deinum Jun 25 '14 at 08:44
  • I wouldn't throw an exception but just add `throws IOException` if something goes wrong loading the resources you probably don't want to start your application. – M. Deinum Jun 25 '14 at 09:22
  • thanks. good point :) – alizelzele Jun 25 '14 at 09:25
  • Modified answer to reflect this also. – M. Deinum Jun 25 '14 at 09:36

1 Answers1

6

You need to use a ResourcePatternResolver to translate classpath*:dozer/**/*.dzr.xml into a Resource[]. There are 2 main options you can use.

  1. Inject the ApplicationContext into your configuration class, cast it to a ResourcePatternResolver and use the getResources method. Al Spring default application context implementations implement the ResourcePatternResolver interface.
  2. Create a PathMatchingResourcePatternResolver with or without the earlier mentioned context.
  3. Use the ResourcePatternUtils with an injected ResourceLoader.

Use the ResourcePatternUtils

@Configuration
public class MyConfiguration {

    @Autowired
    private ResourceLoader resourceLoader;

    public DozerBeanMapperFactoryBean mapper() throws IOException {
        DozerBeanMapperFactoryBean mapper = new DozerBeanMapperFactoryBean();
        // ResourceLoader is allowed to be null when using the ResourceLoaderUtils.
        ResourcePatternResolver resolver = ResourceLoaderUtils.getResourcePatternResolver(resourceLoader);
        Resource[] mappingFiles = resolver.getResources("classpath*:dozer/**/*.dzr.xml");
        mapper.setMappingFiles(mappingFiles);
        return mapper;
    }
}

The advantages of this last approach is that you aren't tied to the PathMatchingResourcePatternResolver but just the interface. The utility class determines, based on the injected ResourceLoader what it does. One should prefer this way of loading resources.

Using ApplicationContext

@Configuration
public class MyConfiguration {

    @Autowired
    private ApplicationContext context;

    public DozerBeanMapperFactoryBean mapper() throws IOException {
        DozerBeanMapperFactoryBean mapper = new DozerBeanMapperFactoryBean();
        Resource[] mappingFiles = ((ResourcePatternResolver) context).getResources("classpath*:dozer/**/*.dzr.xml");
        mapper.setMappingFiles(mappingFiles);
        return mapper;
    }
}

Using PathMatchingResourcePatternResolver

@Configuration
public class MyConfiguration {

    private PathMatchingPatternResolver resolver = new PathMatchingPatternResolver();

    public DozerBeanMapperFactoryBean mapper() throws IOException {
        DozerBeanMapperFactoryBean mapper = new DozerBeanMapperFactoryBean();
        Resource[] mappingFiles = resolver.getResources("classpath*:dozer/**/*.dzr.xml");
        mapper.setMappingFiles(mappingFiles);
        return mapper;
    }
}

Or if you want to reuse the already existing ResourceLoader a slighty different version:

@Configuration
public class MyConfiguration {

    @Autowired
    private ResourceLoader resourceLoader;

    public DozerBeanMapperFactoryBean mapper() throws IOException {
        DozerBeanMapperFactoryBean mapper = new DozerBeanMapperFactoryBean();
        Resource[] mappingFiles = new PathMatchingPatternResolver(resourceLoader).getResources("classpath*:dozer/**/*.dzr.xml");
        mapper.setMappingFiles(mappingFiles);
        return mapper;
    }
}
M. Deinum
  • 115,695
  • 22
  • 220
  • 224
  • thank you. using PathMatchingPatternResolver solved my problem. autowiring will not work in configuration (maybe because they are not created yet !) i`ll update my question will code. – alizelzele Jun 25 '14 at 09:04
  • `Autowired` works in configuration classes just as for normal components. However there is no `PathMatchingPatternResolver` so that you will have to construct yourself (which is what I also show in the code snippets). Injection of the `ResourceLoader` or `ApplicationContext` should work. – M. Deinum Jun 25 '14 at 09:09
  • injection of `ResourceLoader` or `ApplicationContext' result in Null pointer exception. they are null while application context is initializing – alizelzele Jun 25 '14 at 09:11
  • That should work as I have used it multiple times myself. There must be something weird/wrong in your setup. – M. Deinum Jun 25 '14 at 09:14
  • not being able to autowire `applicationContext` was my problem in first place. where can i put my configuration so that u can see cause adding it as an answer here won't be correct. it is working without any problem. just want to find out where the problem was – alizelzele Jun 25 '14 at 09:20
  • You might want to open a new question for that. Adding your configuration and loading strategy. – M. Deinum Jun 25 '14 at 09:23
  • found the problem. `DozerBeanMapperFactoryBean` implements `FactoryBean`. when creating factories `applicationContext` is not ready for being autowired (didn't dig in the code to find out why, but it make sense). – alizelzele Jun 25 '14 at 10:09
  • It might be due to `@Autowired` however it should work. Instead of `@Autowired` you could try `ResourceLoaderAware`. – M. Deinum Jun 25 '14 at 10:19
  • dig a bit into source. factory beans get created before normal beans. when adding @Autowired in factory bean creator, spring tries to create an instance of ApplicationContext(even if it is not complete). creating ApplicationContext lead to trying to load as much as beans as it can. with contain our Configuration class, which has an ApplicationContext that is Autowired to it. so creating instance of ConfigurationClass fails and after that instance of ApplicationContext fails and .... (never dig into spring core code or u get lost in there :D ) – alizelzele Jun 25 '14 at 11:16