java.lang.TypeNotPresentException from common library

We’re working on building a module that will expose some web services to allow some external control over Ignition. When the Endpoint gets published, it’s throwing a TypeNotPresentException on the interface defined in the Common project. If I add the code to publish the same endpoint to a regular main() method and fire it up locally, it works just fine, so I’m thinking it has to do with the way we’ve built the module. Below is the module definition and the stack trace for the exception. The hook is in the Cell jar, the IProductionOrder is in the Common jar.

Note: For the sake of simplicity, I’ve reduced all the web service hosting down to just Endpoint.publish(“http://localhost:8080/wsServerExample”, new IgnitionCellTierInterface()); It does work in a static void main() method, but does not within AbstractGatewayModuleHook.startup();

[code]<?xml version="1.0" encoding="UTF-8"?>


company-project-cell
Project Cell Module
Description
0.0.0.57-beta1205413474
7.3.0
3
true

	<jar scope="G">company-project-common.jar</jar>
	<jar scope="G">company-project-cell.jar</jar>

	<!-- Tell the Gateway and/or Designer where to find the hooks -->
	<hook scope="G">com.company.project.cell.ignition.IgnitionCellTier</hook>
	
</module>

[/code]

java.lang.TypeNotPresentException: Type com.company.project.common.data.models.IProductionOrder not present at sun.reflect.generics.factory.CoreReflectionFactory.makeNamedType(CoreReflectionFactory.java:98) at sun.reflect.generics.visitor.Reifier.visitClassTypeSignature(Reifier.java:107) at sun.reflect.generics.tree.ClassTypeSignature.accept(ClassTypeSignature.java:31) at sun.reflect.generics.visitor.Reifier.reifyTypeArguments(Reifier.java:50) at sun.reflect.generics.visitor.Reifier.visitClassTypeSignature(Reifier.java:120) at sun.reflect.generics.tree.ClassTypeSignature.accept(ClassTypeSignature.java:31) at sun.reflect.generics.repository.FieldRepository.getGenericType(FieldRepository.java:67) at java.lang.reflect.Field.getGenericType(Field.java:223) at com.sun.xml.internal.bind.v2.model.nav.ReflectionNavigator.getFieldType(ReflectionNavigator.java:262) at com.sun.xml.internal.bind.v2.model.nav.ReflectionNavigator.getFieldType(ReflectionNavigator.java:47) at com.sun.xml.internal.bind.v2.model.impl.FieldPropertySeed.getRawType(FieldPropertySeed.java:63) at com.sun.xml.internal.bind.v2.model.impl.RuntimeClassInfoImpl$RuntimePropertySeed.getRawType(RuntimeClassInfoImpl.java:304) at com.sun.xml.internal.bind.v2.model.impl.RuntimeClassInfoImpl$RuntimePropertySeed.getRawType(RuntimeClassInfoImpl.java:278) at com.sun.xml.internal.bind.v2.model.impl.PropertyInfoImpl.<init>(PropertyInfoImpl.java:108) at com.sun.xml.internal.bind.v2.model.impl.ERPropertyInfoImpl.<init>(ERPropertyInfoImpl.java:42) at com.sun.xml.internal.bind.v2.model.impl.ElementPropertyInfoImpl.<init>(ElementPropertyInfoImpl.java:85) at com.sun.xml.internal.bind.v2.model.impl.RuntimeElementPropertyInfoImpl.<init>(RuntimeElementPropertyInfoImpl.java:48) at com.sun.xml.internal.bind.v2.model.impl.RuntimeClassInfoImpl.createElementProperty(RuntimeClassInfoImpl.java:154) at com.sun.xml.internal.bind.v2.model.impl.ClassInfoImpl.addProperty(ClassInfoImpl.java:857) at com.sun.xml.internal.bind.v2.model.impl.ClassInfoImpl.findFieldProperties(ClassInfoImpl.java:387) at com.sun.xml.internal.bind.v2.model.impl.ClassInfoImpl.getProperties(ClassInfoImpl.java:290) at com.sun.xml.internal.bind.v2.model.impl.RuntimeClassInfoImpl.getProperties(RuntimeClassInfoImpl.java:165) at com.sun.xml.internal.bind.v2.model.impl.ModelBuilder.getClassInfo(ModelBuilder.java:232) at com.sun.xml.internal.bind.v2.model.impl.RuntimeModelBuilder.getClassInfo(RuntimeModelBuilder.java:89) at com.sun.xml.internal.bind.v2.model.impl.RuntimeModelBuilder.getClassInfo(RuntimeModelBuilder.java:70) at com.sun.xml.internal.bind.v2.model.impl.ModelBuilder.getClassInfo(ModelBuilder.java:198) at com.sun.xml.internal.bind.v2.model.impl.RuntimeModelBuilder.getClassInfo(RuntimeModelBuilder.java:84) at com.sun.xml.internal.bind.v2.model.impl.RuntimeModelBuilder.getClassInfo(RuntimeModelBuilder.java:70) at com.sun.xml.internal.bind.v2.model.impl.ModelBuilder.getTypeInfo(ModelBuilder.java:304) at com.sun.xml.internal.bind.v2.model.impl.ModelBuilder.getTypeInfo(ModelBuilder.java:319) at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl.getTypeInfoSet(JAXBContextImpl.java:430) at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl.<init>(JAXBContextImpl.java:277) at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl$JAXBContextBuilder.build(JAXBContextImpl.java:1100) at com.sun.xml.internal.bind.v2.ContextFactory.createContext(ContextFactory.java:143) at com.sun.xml.internal.bind.api.JAXBRIContext.newInstance(JAXBRIContext.java:95) at com.sun.xml.internal.ws.developer.JAXBContextFactory$1.createJAXBContext(JAXBContextFactory.java:97) at com.sun.xml.internal.ws.model.AbstractSEIModelImpl$1.run(AbstractSEIModelImpl.java:148) at com.sun.xml.internal.ws.model.AbstractSEIModelImpl$1.run(AbstractSEIModelImpl.java:140) at java.security.AccessController.doPrivileged(Native Method) at com.sun.xml.internal.ws.model.AbstractSEIModelImpl.createJAXBContext(AbstractSEIModelImpl.java:140) at com.sun.xml.internal.ws.model.AbstractSEIModelImpl.postProcess(AbstractSEIModelImpl.java:83) at com.sun.xml.internal.ws.model.RuntimeModeler.buildRuntimeModel(RuntimeModeler.java:244) at com.sun.xml.internal.ws.server.EndpointFactory.createSEIModel(EndpointFactory.java:312) at com.sun.xml.internal.ws.server.EndpointFactory.createEndpoint(EndpointFactory.java:178) at com.sun.xml.internal.ws.api.server.WSEndpoint.create(WSEndpoint.java:456) at com.sun.xml.internal.ws.api.server.WSEndpoint.create(WSEndpoint.java:475) at com.sun.xml.internal.ws.transport.http.server.EndpointImpl.createEndpoint(EndpointImpl.java:213) at com.sun.xml.internal.ws.transport.http.server.EndpointImpl.publish(EndpointImpl.java:143) at com.sun.xml.internal.ws.spi.ProviderImpl.createAndPublishEndpoint(ProviderImpl.java:102) at javax.xml.ws.Endpoint.publish(Endpoint.java:170) at com.company.project.cell.ignition.IgnitionCellTier.startup(IgnitionCellTier.java:86) at com.inductiveautomation.ignition.gateway.modules.ModuleManagerImpl$LoadedModule.startup(ModuleManagerImpl.java:1994) at com.inductiveautomation.ignition.gateway.modules.ModuleManagerImpl.startupModule(ModuleManagerImpl.java:1335) at com.inductiveautomation.ignition.gateway.modules.ModuleManagerImpl$3.call(ModuleManagerImpl.java:888) at com.inductiveautomation.ignition.gateway.modules.ModuleManagerImpl.executeModuleOperation(ModuleManagerImpl.java:1017) at com.inductiveautomation.ignition.gateway.modules.ModuleManagerImpl.installModuleInternal(ModuleManagerImpl.java:868) at com.inductiveautomation.ignition.gateway.modules.ModuleManagerImpl.access$1400(ModuleManagerImpl.java:109) at com.inductiveautomation.ignition.gateway.modules.ModuleManagerImpl$InstallCommand.execute(ModuleManagerImpl.java:1636) at com.inductiveautomation.ignition.gateway.modules.ModuleManagerImpl$Receiver.receiveCall(ModuleManagerImpl.java:1576) at com.inductiveautomation.ignition.gateway.cluster.QueueableMessageReceiver.receiveCall(QueueableMessageReceiver.java:45) at com.inductiveautomation.ignition.gateway.redundancy.RedundancyManagerImpl.dispatchMessage(RedundancyManagerImpl.java:619) at com.inductiveautomation.ignition.gateway.redundancy.RedundancyManagerImpl$ExecuteTask.run(RedundancyManagerImpl.java:640) at com.inductiveautomation.ignition.common.execution.impl.BasicExecutionEngine$ThrowableCatchingRunnable.run(BasicExecutionEngine.java:526) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:441) at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303) at java.util.concurrent.FutureTask.run(FutureTask.java:138) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:98) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:207) at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908) at java.lang.Thread.run(Thread.java:619) Caused by: java.lang.ClassNotFoundException: com.company.project.common.data.models.IProductionOrder at java.net.URLClassLoader$1.run(URLClassLoader.java:200) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:188) at java.lang.ClassLoader.loadClass(ClassLoader.java:307) at java.lang.ClassLoader.loadClass(ClassLoader.java:252) at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:320) at java.lang.Class.forName0(Native Method) at java.lang.Class.forName(Class.java:247) at sun.reflect.generics.factory.CoreReflectionFactory.makeNamedType(CoreReflectionFactory.java:95) ... 70 more

E: Edited to put in correct stack trace, other one was from a previous test and not the latest.

We’ve tried a variety of different scenarios, including rolling the .class files into the same jar, trying to put additional jars like jaxb dependencies in the module (just in case it was crashing on generating the web service), etc. We did try just using the classes as regular objects within the startup and are able to instantiate and get a value from them, so the objects are available, just not to the Endpoint publishing. The only thing that’s worked for that piece is putting the common library on the class path using ignition.conf. At this point I really have no idea why it worked, just that it did. So, with that I’ve got some questions about this solution:

  1. If we’re adding libraries there, will they be usable by clients?
  2. Since this fix is only intended to address the gateway hosting a web service - are there any foreseeable issues with using this on the gateway?
  3. Does this shed any light on why it doesn’t work from within the module? All we did was copy the common.jar to the /lib folder and add a line to Ignition.conf for the # Java Classpath section.

No.

I don't really see anything wrong with it, other than its hacky-ness. More overhead to remember and the like.

We don't use any of the Endpoint / web service stuff, so I don't really know why it doesn't work. My guess it that its trying to load the classes from a ClassLoader above the one that jar files provided by modules are loaded and available in.

Ok, I think we found a way to hack around the class loader issue based on this blog post. Here’s what we ended up with inside of a web service manager to control starting and stopping the web service. We pass in the web service class to be hosted as part of the constructor and that’s where clazz comes from.

ClassLoader oldTCCL = Thread.currentThread().getContextClassLoader(); try { Thread.currentThread().setContextClassLoader(clazz.getClassLoader()); endpoint.publish(context); } catch (Exception e) { logger.error("Unable to start web service.", e); } finally { Thread.currentThread().setContextClassLoader(oldTCCL); }

Cool, glad you got it fixed.

As for making JAR files provided by a module available to clients - the scope in the module.xml influences that. Something scoped “dcg” as opposed to “g” should get sent to the clients.

Another question on this topic - it looks like we’ll be using Ignition as the platform for at least two of the tiers in this architecture, possibly a third. All will need common functionality like this web service, so I tried to make an Ignition-specific common library to create my own AbstractIgnitionTier class (extending AbstractGatewayModuleHook) that all three tiers will extend, but with my first pass at this I’m getting ClassNotFoundException for the AbstractIgnitionTier class. Before I dig into how I’ve set up the module - is it likely facing the same ClassLoader issues?

Is each of the “tiers” its own module? Explain your project/lib setup a little bit more if you can.

Whoops…turns out when I copied the Ant build files, I forgot to give the new project a new jar name, so it was being overwritten by the original common.jar during the module bundling process. It’s working great now!