# Bnd, ServiceLoader and javax.xml.stream.FactoryFinder

**URL:** <https://bnd.discourse.group/t/bnd-serviceloader-and-javax-xml-stream-factoryfinder/250>\
**Category:** GENERAL\
**Created:** [June 16, 2022, 11:03am UTC](https://bnd.discourse.group/t/bnd-serviceloader-and-javax-xml-stream-factoryfinder/250 "2022-06-16T11:03:20Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![chrisr3](https://yyz2.discourse-cdn.com/free1/user_avatar/bnd.discourse.group/chrisr3/32/58_2.png) [@chrisr3](https://bnd.discourse.group/u/chrisr3)\
**Post date:** [June 16, 2022, 11:03am UTC](https://bnd.discourse.group/t/bnd-serviceloader-and-javax-xml-stream-factoryfinder/250/1 "2022-06-16T11:03:20Z")

</div>

Hi,

I am trying to use `javax.xml.stream.XMLInputFactory` and `javax.xml.stream.XMLOutputFactory` inside an OSGi framework. These use `ServiceLoader` internally to locate concrete `XMLInputFactory` and `XMLOutputFactory` classes, i.e. by invoking `javax.xml.stream.FactoryFinder`. However, `FactoryFinder` is part of the JDK and so has no `osgi.serviceloader` metadata.

The only way I know to add extra requirements to Bnd is:

```auto
-runrequires: \
    osgi.serviceloader;filter:='(osgi.serviceloader=javax.xml.stream.XMLInputFactory)';osgi.serviceloader='javax.xml.stream.XMLInputFactory',\
    osgi.serviceloader;filter:='(osgi.serviceloader=javax.xml.stream.XMLOutputFactory)';osgi.serviceloader='javax.xml.stream.XMLOutputFactory',\

```

However, I still get this exception at runtime:

```auto
    => javax.xml.stream.FactoryConfigurationError: Provider for javax.xml.stream.XMLInputFactory cannot be found
       java.xml/javax.xml.stream.FactoryFinder.find(FactoryFinder.java:320)
       java.xml/javax.xml.stream.XMLInputFactory.newFactory(XMLInputFactory.java:323)
       com.fasterxml.jackson.dataformat.xml.XmlFactory.<init>(XmlFactory.java:120)
       com.fasterxml.jackson.dataformat.xml.XmlFactory.<init>(XmlFactory.java:106)
       com.fasterxml.jackson.dataformat.xml.XmlFactory.<init>(XmlFactory.java:90)
       com.fasterxml.jackson.dataformat.xml.XmlMapper.<init>(XmlMapper.java:129)
       com.fasterxml.jackson.dataformat.xml.XmlMapper.builder(XmlMapper.java:220)
       ...

```

FWIW, this is happening with a locally-patched 2.14.0-SNAPSHOT version of Jackson where I have added these Bnd annotations:

```java
package com.fasterxml.jackson.dataformat.xml;

@ServiceProvider(JsonFactory.class)
@ServiceConsumer(XMLInputFactory.class)
@ServiceConsumer(XMLOutputFactory.class)
public class XmlFactory extends JsonFactory

```

However, it occurs to me that it is the _system_ bundle which is the actual “consumer” here, and so maybe that is where the requirement should be. But there is no obvious equivalent of `-runsystemcapabilities` for requirements other than `-runrequires`.

For reference, my `-runbundles` _does_ contain:

```auto
org.apache.aries.spifly.dynamic.bundle;version='[1.3.2,1.3.3)',\

```

Can anyone help me sort my `.bndrun` file out please?  
Thanks,  
Chris

Edit: From the POV of a `TestOSGi` Gradle task, this test fails:

```java
@ServiceConsumer(XMLInputFactory.class)
class ServiceLoaderTest {
    private static final Logger logger = LoggerFactory.getLogger(ServiceLoader.class);

    @Test
    void loadXMLInputFactoryByClassLoader() {
        final XMLInputFactory inputFactory = XMLInputFactory.newFactory(XMLInputFactory.class.getName(), getClass().getClassLoader());
        assertNotNull(inputFactory);
        logger.info("FOUND: {}", inputFactory);
    }
}

```

but this succeeds:

```java
@ServiceConsumer(XMLInputFactory.class)
class ServiceLoaderTest {
    private static final Logger logger = LoggerFactory.getLogger(ServiceLoader.class);

    @Test
    void serviceLoadXMLInputFactory() {
        final ServiceLoader<XMLInputFactory> inputFactoriesLoader = ServiceLoader.load(XMLInputFactory.class, getClass().getClassLoader());
        final List<XMLInputFactory> inputFactories = inputFactoriesLoader.stream().map(ServiceLoader.Provider::get).collect(toList());
        assertThat(inputFactories).isNotEmpty();
        inputFactories.forEach(input -> logger.info("FOUND: {}", input));
    }
}

```

---

<div class="post-metadata">

**Author:** ![chrisr3](https://yyz2.discourse-cdn.com/free1/user_avatar/bnd.discourse.group/chrisr3/32/58_2.png) [@chrisr3](https://bnd.discourse.group/u/chrisr3)\
**Post date:** [June 17, 2022, 10:30am UTC](https://bnd.discourse.group/t/bnd-serviceloader-and-javax-xml-stream-factoryfinder/250/2 "2022-06-17T10:30:26Z")

</div>

Oh, I had thought `@ServiceConsumer` was instructing Aries SpiFly to register a handler on the bundle which would enable `BundleClassLoader.getResources()` to find the correct `META-INF/services` files. I see now that the Aries SpiFly service is actually _rewriting the bundle’s bytecode_ to replace invocations of

```java
java.util.ServiceLoader.load(<service>, <classloader>)

```

with

```java
org.apache.aries.spifly.Util.serviceLoaderLoad(<service>, <caller>)

```

This rather scuppers my plans for World Domination… 🤦‍♂️

Thanks anyway,  
Cheers,  
Chris

---

<div class="post-metadata">

**Author:** ![chrisr3](https://yyz2.discourse-cdn.com/free1/user_avatar/bnd.discourse.group/chrisr3/32/58_2.png) [@chrisr3](https://bnd.discourse.group/u/chrisr3)\
**Post date:** [June 17, 2022, 4:00pm UTC](https://bnd.discourse.group/t/bnd-serviceloader-and-javax-xml-stream-factoryfinder/250/3 "2022-06-17T16:00:52Z")

</div>

It’s not difficult to extend the Aries SPI-Fly also to weave for these methods:

```auto
javax.xml.stream.XMLInputFactory.newFactory(String, ClassLoader)
javax.xml.stream.XMLOutputFactory.newFactory(String, ClassLoader)
javax.xml.stream.XMLEventFactory.newFactory(String, ClassLoader)

```

By which I mean I have created a 1.4.0-SNAPSHOT version locally which seems to work.

But I suppose the more interesting question here is “Why didn’t someone implement this already?”. Does this go against the OSGi Spec somehow?

Cheers,  
Chris

---

<div class="post-metadata">

**Author:** ![rotty3000](https://yyz2.discourse-cdn.com/free1/user_avatar/bnd.discourse.group/rotty3000/32/16_2.png) [@rotty3000](https://bnd.discourse.group/u/rotty3000)\
**Post date:** [June 17, 2022, 4:25pm UTC](https://bnd.discourse.group/t/bnd-serviceloader-and-javax-xml-stream-factoryfinder/250/4 "2022-06-17T16:25:50Z")

</div>

what comes to mind is [http://docs.osgi.org/specification/osgi.cmpn/7.0.0/util.xml.html](http://docs.osgi.org/specification/osgi.cmpn/7.0.0/util.xml.html) and IIRC that there’s some of this built into Equinox (not sure about Apache Felix).

---

<div class="post-metadata">

**Author:** ![laeubi](https://yyz2.discourse-cdn.com/free1/user_avatar/bnd.discourse.group/laeubi/32/131_2.png) [@laeubi](https://bnd.discourse.group/u/laeubi)\
**Post date:** [June 18, 2022, 7:58am UTC](https://bnd.discourse.group/t/bnd-serviceloader-and-javax-xml-stream-factoryfinder/250/5 "2022-06-18T07:58:12Z")

</div>

Just wanted to let you know that for all the jax-stuff if you want to make it aviable you can simply use [https://mvnrepository.com/artifact/org.glassfish.hk2/hk2-locator](https://mvnrepository.com/artifact/org.glassfish.hk2/hk2-locator)

---

<div class="post-metadata">

**Author:** ![chrisr3](https://yyz2.discourse-cdn.com/free1/user_avatar/bnd.discourse.group/chrisr3/32/58_2.png) [@chrisr3](https://bnd.discourse.group/u/chrisr3)\
**Post date:** [June 18, 2022, 10:31pm UTC](https://bnd.discourse.group/t/bnd-serviceloader-and-javax-xml-stream-factoryfinder/250/6 "2022-06-18T22:31:05Z")

</div>

Hi, thanks for replying.

I am actually trying to use a library which has `jackson-dataformat-xml` as one of its dependencies, so I don’t believe OSGi’s `util.xml` will help me here. Jackson’s bundles are all missing the `@ServiceProvider` annotations for their `META-INF/services/*` files, which I can fix. However, I cannot reasonably add `@ServiceConsumer` annotations for their XML `newFactory()` method invocations if this isn’t covered by the OSGi spec 😢.

Perhaps the best solution would be to create a SPI-Fly-like bundle to weave for just the XML factories, targeting (say) bundles that require the `javax.xml.streams` package? Or just targeting a hard-coded set of bundle symbolic names, if that’s not possible.

Cheers,  
Chris

---

<div class="post-metadata">

**Author:** ![chrisr3](https://yyz2.discourse-cdn.com/free1/user_avatar/bnd.discourse.group/chrisr3/32/58_2.png) [@chrisr3](https://bnd.discourse.group/u/chrisr3)\
**Post date:** [June 20, 2022, 2:12pm UTC](https://bnd.discourse.group/t/bnd-serviceloader-and-javax-xml-stream-factoryfinder/250/7 "2022-06-20T14:12:55Z")

</div>

Hi,

I think there’s a problem with Apache Aries `spi-fly`, but its GitHub repo isn’t allowing me to raise an issue for it 🤦‍♂️.

Suppose a class wishes to “consume” `TypeA` but produce `TypeB`, and so is annotated as

```java
@ServiceProvider(TypeB.class)
@ServiceConsumer(TypeA.class)
public class MyClass implements TypeB {
    // etc
}

```

If the OSGi framework executes the `ProviderBundleTrackerCustomizer` for this bundle before executing the `ConsumerBundleTrackerCustomizer` then the `ProviderBundleTrackerCustomizer` will load `MyClass` before the `ConsumerBundleTrackerCustomizer` has had an opportunity to register its “weaving data”. This means that `MyClass` will not be woven, of course.

I fixed this locally by copying

```java
try {
    activator.addConsumerWeavingData(bundle, consumerHeaderName);
} catch (Exception e) {
     throw new RuntimeException(e.getMessage(), e);
}

```

to the top of `ProviderBundleTrackerCustomizer#addBundles`, but _ideally_ I’d prefer for `ProviderBundleTrackerCustomizer` to defer loading `MyClass` until every `WeavingHook` is “ready”. (I have no idea how to achieve that, however… 🙁).

Cheers,  
Chris

---

<div class="post-metadata">

**Author:** ![rotty3000](https://yyz2.discourse-cdn.com/free1/user_avatar/bnd.discourse.group/rotty3000/32/16_2.png) [@rotty3000](https://bnd.discourse.group/u/rotty3000)\
**Post date:** [June 20, 2022, 2:39pm UTC](https://bnd.discourse.group/t/bnd-serviceloader-and-javax-xml-stream-factoryfinder/250/8 "2022-06-20T14:39:23Z")

</div>

Chris, Apache Aries aries, like every other Apache project uses JIRA for issue management/bug tracking → [ARIES JIRA](https://issues.apache.org/jira/projects/ARIES/issues/ARIES-1703?filter=allopenissues)

---

<div class="post-metadata">

**Author:** ![rotty3000](https://yyz2.discourse-cdn.com/free1/user_avatar/bnd.discourse.group/rotty3000/32/16_2.png) [@rotty3000](https://bnd.discourse.group/u/rotty3000)\
**Post date:** [June 20, 2022, 2:41pm UTC](https://bnd.discourse.group/t/bnd-serviceloader-and-javax-xml-stream-factoryfinder/250/9 "2022-06-20T14:41:20Z")

</div>

Also before you go down the path of writing any code did you try this feature of Aries SPI Fly: [https://aries.apache.org/documentation/modules/spi-fly.html#\_dynamic\_weaving\_by\_auto\_properties](https://aries.apache.org/documentation/modules/spi-fly.html#_dynamic_weaving_by_auto_properties)

---

<div class="post-metadata">

**Author:** ![rotty3000](https://yyz2.discourse-cdn.com/free1/user_avatar/bnd.discourse.group/rotty3000/32/16_2.png) [@rotty3000](https://bnd.discourse.group/u/rotty3000)\
**Post date:** [June 20, 2022, 2:44pm UTC](https://bnd.discourse.group/t/bnd-serviceloader-and-javax-xml-stream-factoryfinder/250/10 "2022-06-20T14:44:42Z")

</div>

Finally, to avoid all startup ordering issues, please use

```auto

```

 org.apache.aries.spifly org.apache.aries.spifly.dynamic.framework.extension ${spifly.version} ```

```auto

Instead of the other dependencies, because that one ensures that bundles are handled only when the framework extension has made the capabilities for SLM (Service Loader Mediator) available which means the weaver is available, and means it's impossible for other bundles that use the capability to resolve (and therefore start) before it.
```

---

<div class="post-metadata">

**Author:** ![chrisr3](https://yyz2.discourse-cdn.com/free1/user_avatar/bnd.discourse.group/chrisr3/32/58_2.png) [@chrisr3](https://bnd.discourse.group/u/chrisr3)\
**Post date:** [June 20, 2022, 3:21pm UTC](https://bnd.discourse.group/t/bnd-serviceloader-and-javax-xml-stream-factoryfinder/250/11 "2022-06-20T15:21:15Z")

</div>

Thanks, I was about to investigate the mysteries of `WovenClassListener`, but switching from `org.apache.aries.spifly.dynamic.bundle` to `org.apache.aries.spifly.dynamic.framework.extension` seems to resolved the ordering issue with the weaving.

I doubt `spi-fly`’s “auto properties” feature will help me because I really need to weave for consumers of `XMLInputFactory.newFactory` etc rather than `ServiceLoader.load`. I’ve been hacking on `spi-fly` locally just to prove that I can get something to work, but ultimately I would need for my own custom `WeavingHook` to execute before `spi-fly` registers the providers with the framework.

I am assuming here that `spi-fly` would _never_ support weaving for consumers of `XML(Input|Output|Event)Factory.newFactory` via Bnd’s `@ServiceConsumer` annotation.

Cheers,  
Chris

---

<div class="post-metadata">

**Author:** ![chrisr3](https://yyz2.discourse-cdn.com/free1/user_avatar/bnd.discourse.group/chrisr3/32/58_2.png) [@chrisr3](https://bnd.discourse.group/u/chrisr3)\
**Post date:** [June 21, 2022, 2:05pm UTC](https://bnd.discourse.group/t/bnd-serviceloader-and-javax-xml-stream-factoryfinder/250/12 "2022-06-21T14:05:07Z")

</div>

Raised as [ARIES-2077](https://issues.apache.org/jira/browse/ARIES-2077).
