Bharimalla
Bharimalla

Reputation: 41

Dozer: ClassNotFoundException in Osgi Environment

I am using Dozer in Osgi environement(Apache karaf). Version user 5.4.0. Pom dependency looks like below.

    <dependency>
        <groupId>net.sf.dozer</groupId>
        <artifactId>dozer-osgi</artifactId>
        <version>5.4.0</version>
    </dependency>

We are using custom mapping thru xml file. When dozer mapper refers to the mapping xml for a mapping, it is not getting the class referred in the the file. I get following exception.

2014-05-07 00:12:13,734[qtp1876495841-122]|ERROR|com.ge.alsp.dspkservice.services.impl.UserServiceImpl|354-alsp-service-2.0.0|Failed to get user profile.
org.dozer.MappingException: java.lang.ClassNotFoundException: com.ge.alsp.model.usermanagement.Timezone not found from bundle [dsp.core]
    at org.dozer.util.MappingUtils.throwMappingException(MappingUtils.java:82)
    at org.dozer.util.DefaultClassLoader.loadClass(DefaultClassLoader.java:38)
    at org.dozer.util.MappingUtils.loadClass(MappingUtils.java:224)
    at org.dozer.loader.DozerBuilder$MappingBuilder.classA(DozerBuilder.java:129)
    at org.dozer.loader.xml.XMLParser.parseMapping(XMLParser.java:188)
    at org.dozer.loader.xml.XMLParser.read(XMLParser.java:135)
    at org.dozer.loader.xml.XMLParser.read(XMLParser.java:43)
    at org.dozer.loader.xml.MappingStreamReader.read(MappingStreamReader.java:51)
    at org.dozer.loader.xml.MappingFileReader.read(MappingFileReader.java:58)
    at org.dozer.DozerBeanMapper.loadFromFiles(DozerBeanMapper.java:227)

Any idea how to make dozer work in osgi ?

Upvotes: 0

Views: 3405

Answers (3)

John Georgiadis
John Georgiadis

Reputation: 171

Dozer employs a class loader for loading at least the following resources:

  • Mapping definition XML files. A mapping definition file contains custom mapping rules.
  • Classes based on the fully qualified class name using Class.forName().

Dozer has a pluggable class loading configuration which allows to set a custom class loader for classes and resources:

org.dozer.util.DozerClassLoader classLoader=...;
BeanContainer.getInstance().setClassLoader(classLoader);  

However Dozer was not designed with OSGi in mind. Custom class loaders are set on a Dozer singleton. This combined with the lazy loading of mapping definition files can generate unexpected results.

Since the classloader is set on a singleton, it affects all bundles that import resources through Dozer. However if the following conditions are valid then an acceptable workaround can be implemented:

  • Bundles are started sequentially.
  • Dozer is setup completely during the bundle’s startup phase.

The first condition will prevent the class loader property of the BeanContainer to be overridden until a bundle has started.

The second condition will allow Dozer to load any custom mapping files and all classes referenced in them before the BeanContainer singleton is reset by another bundle.

The only missing pieces are the custom Dozer class loader, and the Dozer initialization in the bundle.

The Dozer class loader that delegates to the bundle’s class loader is shown below:

public class OsgiDozerClassLoader implements DozerClassLoader {
private BundleContext context;

@Override
public Class<?> loadClass(String className) {
    try {
        return context.getBundle().loadClass(className);
    } catch (ClassNotFoundException e) {
        return null;
    }
}

@Override
public URL loadResource(String uri) {
    URL url;

    url = context.getBundle().getResource(uri);

    if (url == null) {
        url = DozerClassLoader.class.getClassLoader().getResource(uri);
    }

    return url;
}

public void setContext(BundleContext context) {
    this.context = context;
}
}

Then during bundle startup – e.g. in a blueprint eagerly created bean constructor or init-method – setup the custom classloader, the mapping files and force parsing of the mapping files:

public DozerBeanMapper getMapper(List<String> files) {
    BeanContainer.getInstance().setClassLoader(classLoader);

    DozerBeanMapper mapper = new DozerBeanMapper();
    mapper.setMappingFiles(files);

    // Force loading of the dozer.xml now instead of loading it
    // upon the first mapping call
    mapper.getMappingMetadata();

    return mapper;
}

The above approach is not optimal. In practice it seems to work and its a viable workaround until singletons are removed & class loading becomes more OSGi-friendly in Dozer.

This answer has been adapted from my blog: http://modio.io/dozer-pojo-mapper-in-osgi/

Upvotes: 2

Srikanth Hugar
Srikanth Hugar

Reputation: 385

Can you make sure whether dozer bundle is active in Apache Karaf? You can check via webconsole or command.

I am using below artifact in OSGI (Apache Karaf ) and works for me

    <dependency>
        <groupId>net.sf.dozer</groupId>
        <artifactId>dozer</artifactId>
        <version>5.4.0</version>
    </dependency>

Upvotes: 0

Achim Nierbeck
Achim Nierbeck

Reputation: 5285

Looks like you need to import the acording package to the "dsp.core" bundle. As long as this doesn't import that package dozer isn't able to access it.

Upvotes: 0

Related Questions