Separate classloader with xstream bundled
Hello,
I'm trying to change our plugin to use separate classloder.
I'm having difficulties with XStream, our plugin is built with Maven and has a compile dependency of com.thoughtworks.xstream:xstream:1.4.2
When I try to read an XML file configuration I'm getting the following exception:
Caused by: com.thoughtworks.xstream.io.StreamException: Cannot create XmlPullParser at com.thoughtworks.xstream.io.xml.AbstractXppDriver.createReader(AbstractXppDriver.java:56) at com.thoughtworks.xstream.io.xml.AbstractXppDriver.createReader(AbstractXppDriver.java:65) at com.thoughtworks.xstream.XStream.fromXML(XStream.java:921)
I understand TeamCity bundles XStream, can I use it instead with my plugin?
Where can i find information about this?
Thanks,
Shay.
Please sign in to leave a comment.
Hello,
Yes, we bundle our old version of XStream.
You need to do the following:
- use serate classloader on server check you have
<deployment use-separate-classloader="true"/>
- make sure you have teamcity-plugin.xml in the root of agent plugin with the following content
<teamcity-agent-plugin xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:shemas-jetbrains-com:teamcity-agent-plugin-v1-xml">
<plugin-deployment use-separate-classloader="true"/>
</teamcity-agent-plugin>
- make sure you specify classloader when you create XStream object in the plugin. You may use getClass().getClassloader() from any of your plugin classes to get right classloader for plugin
- you may also need to change Thread;s context classloader for the time of your method call(s). Please make sure you replace it back on any method exit
Hope this helps, please let me know if you have more issues.
OK here is some more information, I've tried 2 ways:
1. XStream is packaged as "compile" with my plugin, it is presented in my final plugin zip both in server directory jars and in the agent zip jars, my project defines:
<dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.4.2</version>
</dependency>
This causes the Exception I wrote before, the code in my plugin is (trimmed a bit)
public class ArtifactoryServerListener extends BuildServerAdapter {
private SBuildServer server;
private ServerConfigPersistenceManager configPersistenceManager;
public ArtifactoryServerListener(@NotNull final EventDispatcher<BuildServerListener> dispatcher,
@NotNull final SBuildServer server, @NotNull ServerPaths serverPaths) {
this.server = server;
dispatcher.addListener(this);
configPersistenceManager = new ServerConfigPersistenceManager(serverPaths);
}
// More fun stuff here..
}
And
public class ServerConfigPersistenceManager {
private final static String CONFIG_FILE_NAME = "artifactory-config.xml";
private File configFile;
private XStream xStream;
public ServerConfigPersistenceManager(@NotNull ServerPaths serverPaths) {
xStream = new XStream();
xStream.setClassLoader(SerializableServers.class.getClassLoader());
xStream.processAnnotations(new Class[]{SerializableServer.class, SerializableServers.class}); // These are 2 classes i want to transform from the given XML file
configFile = new File(serverPaths.getConfigDir(), CONFIG_FILE_NAME);
loadSettings();
}
private void loadSettings() {
FileInputStream inputStream = null;
inputStream = new FileInputStream(configFile);
SerializableServers serverConfigs = (SerializableServers) xStream.fromXML(inputStream); // this line caused the exception
}
}
2. My second approuch was settings the XStream dependency as "provided" (by TeamCity), the issue here is it seems as TeamCity is unable to see my classes (SerializableServer.class, SerializableServers.class)
so it cannot convert the XML file to my classes (I thought separate class loader means only between plugins but not between TeamCity server itself), here is what I get now:
[2013-04-29 17:24:56,595] INFO - rver.plugins.PluginManagerImpl - Plugins initialization started...
[2013-04-29 17:24:56,596] INFO - rver.plugins.PluginManagerImpl - Scanning plugins folders
[2013-04-29 17:24:56,597] INFO - .plugins.files.JarSearcherBase - Scanning plugin folder: C:\dev\apache-tomcat-7.0.39-teamcity-7.1.5\webapps\teamcity\WEB-INF\plugins
[2013-04-29 17:24:57,602] INFO - .plugins.files.JarSearcherBase - Scanning plugin folder: C:\TeamCity\BuildServer\plugins
[2013-04-29 17:24:57,759] INFO - rver.plugins.PluginManagerImpl - Found 65 plugins: [agent-system-info (ver:24400), agent.push (ver:24400), Ant (ver:24400), Apache Ant (ver:24400), artifactory (ver:2.1.x-SNAPSHOT), artifactsSizeStatistics (ver:24400), assembly-info-patcher (ver:24400), bugzilla (ver:24400), buildDurationStatisticsPlugin (ver:24400), changeViewers (ver:24400), clearcase (ver:24400), cloud-amazon (ver:24400), commandLineRunner (ver:24400), coverage (ver:24400), cvs (ver:24400), dotnet-tools (ver:24400), dotNetRunners (ver:24400), Duplicator (ver:24400), email (ver:24400), environment-fetcher (ver:24400), feed (ver:24400), FxCop (ver:24400), gant-tool (ver:24400), GAntRunner (ver:24400), gradle-runner (ver:24400), idea-tool (ver:24400), Inspection (ver:24400), Ipr (ver:24400), jabber (ver:24400), Java Crashed detector (ver:24400), java-dowser (ver:24400), jetbrains.git (ver:24400), jira (ver:24400), jps-tool (ver:24400), jvm-update (ver:24400), ldap (ver:24400), maven-tool (ver:24400), Maven2 (ver:24400), maven3-tool (ver:24400), mercurial (ver:24400), ntlm-auth-scheme (ver:24400), nuget (ver:24400), perfmon (ver:24400), perforce (ver:24400), powershell-runner (ver:24400), priority-queue (ver:24400), rake-runner (ver:24400), remoteAccess (ver:24400), rest-api (ver:24400), rest-api-6.0 (ver:24400), searchBuildByNumber (ver:24400), stacktraces (ver:24400), starteam (ver:24400), svn (ver:24400), swabra (ver:24400), tfs (ver:24400), usage-statistics (ver:24400), vault-vcs (ver:24400), vs-addin-distributor (ver:24400), vss (ver:24400), WindowsTray (ver:24400), WindowsTray-distributor (ver:24400), xcode-runner (ver:24400), xml-report-plugin (ver:24400), youtrack (ver:24400)]
[2013-04-29 17:24:57,960] INFO - rver.plugins.PluginsCollection - Load standalone classloaders for 24 plugins [agent-system-info, agent.push, artifactory, assembly-info-patcher, bugzilla, cloud-amazon, dotnet-tools, dotNetRunners, FxCop, java-dowser, jira, jvm-update, Maven2, nuget, perforce, powershell-runner, rake-runner, rest-api, rest-api-6.0, tfs, usage-statistics, vs-addin-distributor, WindowsTray-distributor, xcode-runner]
[2013-04-29 17:24:57,960] INFO - rver.plugins.PluginsCollection - Load shared classloader for 41 plugins [Ant, Apache Ant, artifactsSizeStatistics, buildDurationStatisticsPlugin, changeViewers, clearcase, commandLineRunner, coverage, cvs, Duplicator, email, environment-fetcher, feed, gant-tool, GAntRunner, gradle-runner, idea-tool, Inspection, Ipr, jabber, Java Crashed detector, jetbrains.git, jps-tool, ldap, maven-tool, maven3-tool, mercurial, ntlm-auth-scheme, perfmon, priority-queue, remoteAccess, searchBuildByNumber, stacktraces, starteam, svn, swabra, vault-vcs, vss, WindowsTray, xml-report-plugin, youtrack]
[2013-04-29 17:25:05,899] ERROR - gins.spring.SpringPluginLoader - Failed to initialize spring context for plugin artifactory
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'artifactoryListener' defined in URL [file:/C:/dev/apache-tomcat-7.0.39-teamcity-7.1.5/temp/spring-artifactory3606746830253360742-spring.config.tmp.xml]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [org.jfrog.teamcity.server.global.ArtifactoryServerListener]: Constructor threw exception; nested exception is com.thoughtworks.xstream.mapper.CannotResolveClassException: org.jfrog.teamcity.api.SerializableServers
at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:288)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1003)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:907)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:485)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:291)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:288)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:190)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:580)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:895)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:425)
at jetbrains.buildServer.plugins.spring.SpringPluginLoader$1.configsExtracted(SpringPluginLoader.java:65)
at jetbrains.buildServer.plugins.spring.SpringPluginConfigExtracter.start(SpringPluginConfigExtracter.java:42)
at jetbrains.buildServer.plugins.spring.SpringPluginLoader.pluginClassesLoaded(SpringPluginLoader.java:73)
at sun.reflect.GeneratedMethodAccessor49.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at jetbrains.buildServer.util.EventDispatcher.dispatch(EventDispatcher.java:115)
at jetbrains.buildServer.util.EventDispatcher$2.invoke(EventDispatcher.java:67)
at sun.proxy.$Proxy6.pluginClassesLoaded(Unknown Source)
at jetbrains.buildServer.plugins.PluginManagerImpl$2.visitPlugin(PluginManagerImpl.java:122)
at jetbrains.buildServer.plugins.PluginsCollection.foreachLoadedPlugins(PluginsCollection.java:107)
at jetbrains.buildServer.plugins.PluginManagerImpl.firePluginClassesLoaded(PluginManagerImpl.java:120)
at jetbrains.buildServer.plugins.PluginManagerImpl.loadPlugins(PluginManagerImpl.java:80)
at jetbrains.buildServer.web.plugins.PluginManagerConfigurator.initializePlugins(PluginManagerConfigurator.java:2)
at jetbrains.buildServer.web.impl.BuildServerConfigurator.loadConfiguration(BuildServerConfigurator.java:31)
at jetbrains.buildServer.maintenance.TeamCityDispatcherServlet$WebApplicationCreatorAndDestroyer.createApplication(TeamCityDispatcherServlet.java:17)
at jetbrains.buildServer.maintenance.StartupProcessor.doApplicationStarting(StartupProcessor.java:137)
at jetbrains.buildServer.maintenance.StartupProcessor.processConcreteStage(StartupProcessor.java:369)
at jetbrains.buildServer.maintenance.StartupProcessor.processConcreteStageSafe(StartupProcessor.java:20)
at jetbrains.buildServer.maintenance.StartupProcessor.processTeamCityLifecycle(StartupProcessor.java:378)
at jetbrains.buildServer.maintenance.StartupProcessor.access$000(StartupProcessor.java:507)
at jetbrains.buildServer.maintenance.StartupProcessor$1.run(StartupProcessor.java:1)
at java.lang.Thread.run(Thread.java:722)
Caused by: org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [org.jfrog.teamcity.server.global.ArtifactoryServerListener]: Constructor threw exception; nested exception is com.thoughtworks.xstream.mapper.CannotResolveClassException: org.jfrog.teamcity.api.SerializableServers
at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:141)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:108)
at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:280)
... 34 more
Caused by: com.thoughtworks.xstream.mapper.CannotResolveClassException: org.jfrog.teamcity.api.SerializableServers
at com.thoughtworks.xstream.mapper.DefaultMapper.realClass(DefaultMapper.java:56)
at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:30)
at com.thoughtworks.xstream.mapper.DynamicProxyMapper.realClass(DynamicProxyMapper.java:55)
at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:30)
at com.thoughtworks.xstream.mapper.PackageAliasingMapper.realClass(PackageAliasingMapper.java:88)
at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:30)
at com.thoughtworks.xstream.mapper.ClassAliasingMapper.realClass(ClassAliasingMapper.java:77)
at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:30)
at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:30)
at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:30)
at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:30)
at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:30)
at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:30)
at com.thoughtworks.xstream.mapper.ArrayMapper.realClass(ArrayMapper.java:87)
at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:30)
at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:30)
at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:30)
at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:30)
at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:30)
at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:30)
at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:30)
at com.thoughtworks.xstream.mapper.CachingMapper.realClass(CachingMapper.java:42)
at com.thoughtworks.xstream.core.util.HierarchicalStreams.readClassType(HierarchicalStreams.java:29)
at com.thoughtworks.xstream.core.TreeUnmarshaller.start(TreeUnmarshaller.java:133)
at com.thoughtworks.xstream.core.AbstractTreeMarshallingStrategy.unmarshal(AbstractTreeMarshallingStrategy.java:32)
at com.thoughtworks.xstream.XStream.unmarshal(XStream.java:974)
at com.thoughtworks.xstream.XStream.unmarshal(XStream.java:958)
at com.thoughtworks.xstream.XStream.fromXML(XStream.java:901)
at org.jfrog.teamcity.server.global.ServerConfigPersistenceManager.loadSettings(ServerConfigPersistenceManager.java:69)
at org.jfrog.teamcity.server.global.ServerConfigPersistenceManager.<init>(ServerConfigPersistenceManager.java:61)
at org.jfrog.teamcity.server.global.ArtifactoryServerListener.<init>(ArtifactoryServerListener.java:45)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:525)
at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:126)
... 36 more
Hello,
Please check you have only one instance of the plugin under TeamCity. The exception you have may be caused by extra SerializableServers class that is found under wrong classloader.
The parameter in xml that I asked to update changes the way how TeamCity loads your classes. with 'use-separate-classloader='true'' your classes will be loaded into per-plugin classloader that prefers it's onw classpath to TeamCity classpath. This means it allows to have several versions of same library running.
Do you have the missing class and everything that is called in static from it under plugin binaries?