在 Spring Boot 应用程序中使用 Rackspace 时出现 Apache jclouds java.lang.NoSuchMethodError
Posted
技术标签:
【中文标题】在 Spring Boot 应用程序中使用 Rackspace 时出现 Apache jclouds java.lang.NoSuchMethodError【英文标题】:Apache jclouds java.lang.NoSuchMethodError when using Rackspace in a Spring Boot application 【发布时间】:2017-01-29 15:13:45 【问题描述】:我正在尝试将 Apache Jclouds 集成到我正在开发的 Spring Boot 应用程序中,以便我可以将文件上传到 Rackspace Cloud Files(UK)。
我创建了一个类,我将其创建为 Bean;
import com.google.common.io.ByteSource;
import com.google.common.io.Files;
import org.jclouds.ContextBuilder;
import org.jclouds.io.Payload;
import org.jclouds.io.Payloads;
import org.jclouds.openstack.swift.v1.features.ObjectApi;
import org.jclouds.rackspace.cloudfiles.v1.CloudFilesApi;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* Class WebStorage
*
*/
public class WebStorage
private final String region = "lon";
private final String provider = "rackspace-cloudfiles-uk";
private String username;
private String apiKey;
private String container;
private String url;
private CloudFilesApi cloudFilesApi;
public WebStorage(String username, String apiKey, String container, String url)
this.username = username;
this.apiKey = apiKey;
this.container = container;
this.url = url;
cloudFilesApi = ContextBuilder.newBuilder(provider)
.credentials(this.username, this.apiKey)
.buildApi(CloudFilesApi.class);
/**
* Accepts a MultipartFile and returns it as a File
* @param multipartFile the MultiPartFile to convert
* @return a new File
*/
public static File createFileFromMultipart(MultipartFile multipartFile)
File file = new File(multipartFile.getOriginalFilename());
try
file.createNewFile();
FileOutputStream fos = new FileOutputStream(file);
fos.write(multipartFile.getBytes());
fos.close();
catch (IOException e)
e.printStackTrace();
return file;
/**
* Send the file to the CDN and return it's full URL
* @param name the path/name of the file on the CDN
* @param theFile the file to upload to the CDN
* @return the full URL to the uploaded file on the CDN
*/
public String put(String name, File theFile)
ObjectApi objectApi = cloudFilesApi.getObjectApi(region, this.container);
/* Upload the file */
ByteSource byteSource = Files.asByteSource(theFile);
Payload filePayload = Payloads.newByteSourcePayload(byteSource);
objectApi.put(name, filePayload);
return this.url + name;
我在声明所有其他 bean 的同一个地方声明 bean(工作正常);
@Bean
public WebStorage storage()
return new WebStorage(
env.getProperty("voila.cdn.username"),
env.getProperty("voila.cdn.apikey"),
env.getProperty("voila.cdn.container"),
env.getProperty("voila.cdn.url")
);
但每次我运行应用程序时,bean 都无法加载,因为在尝试创建 bean 时会生成类未找到错误。
2016-09-21 12:19:06.847 ERROR 14911 --- [ restartedMain] o.s.boot.SpringApplication : Application startup failed
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'userController': Unsatisfied dependency expressed through field 'storage': Error creating bean with name 'storage' defined in class path resource [com/appapi/config/AppConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.appapi.helpers.WebStorage]: Factory method 'storage' threw exception; nested exception is java.lang.NoSuchMethodError: com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.<init>(Lcom/google/gson/internal/ConstructorConstructor;Lcom/google/gson/FieldNamingStrategy;Lcom/google/gson/internal/Excluder;)V; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'storage' defined in class path resource [com/appapi/config/AppConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.appapi.helpers.WebStorage]: Factory method 'storage' threw exception; nested exception is java.lang.NoSuchMethodError: com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.<init>(Lcom/google/gson/internal/ConstructorConstructor;Lcom/google/gson/FieldNamingStrategy;Lcom/google/gson/internal/Excluder;)V
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:569) ~[spring-beans-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88) ~[spring-beans-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:349) ~[spring-beans-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1214) ~[spring-beans-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:543) ~[spring-beans-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482) ~[spring-beans-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306) ~[spring-beans-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) ~[spring-beans-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302) ~[spring-beans-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197) ~[spring-beans-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:776) ~[spring-beans-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:861) ~[spring-context-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:541) ~[spring-context-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:122) ~[spring-boot-1.4.0.RELEASE.jar:1.4.0.RELEASE]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:759) [spring-boot-1.4.0.RELEASE.jar:1.4.0.RELEASE]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:369) [spring-boot-1.4.0.RELEASE.jar:1.4.0.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:313) [spring-boot-1.4.0.RELEASE.jar:1.4.0.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1185) [spring-boot-1.4.0.RELEASE.jar:1.4.0.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1174) [spring-boot-1.4.0.RELEASE.jar:1.4.0.RELEASE]
at com.appapi.VoilaApplication.main(VoilaApplication.java:12) [classes/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_25]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_25]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_25]
at java.lang.reflect.Method.invoke(Method.java:483) ~[na:1.8.0_25]
at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49) [spring-boot-devtools-1.4.0.RELEASE.jar:1.4.0.RELEASE]
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'storage' defined in class path resource [com/appapi/config/AppConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.appapi.helpers.WebStorage]: Factory method 'storage' threw exception; nested exception is java.lang.NoSuchMethodError: com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.<init>(Lcom/google/gson/internal/ConstructorConstructor;Lcom/google/gson/FieldNamingStrategy;Lcom/google/gson/internal/Excluder;)V
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:599) ~[spring-beans-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1123) ~[spring-beans-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1018) ~[spring-beans-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:510) ~[spring-beans-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482) ~[spring-beans-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306) ~[spring-beans-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) ~[spring-beans-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302) ~[spring-beans-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) ~[spring-beans-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:207) ~[spring-beans-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1214) ~[spring-beans-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1054) ~[spring-beans-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1019) ~[spring-beans-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:566) ~[spring-beans-4.3.2.RELEASE.jar:4.3.2.RELEASE]
... 24 common frames omitted
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.appapi.helpers.WebStorage]: Factory method 'storage' threw exception; nested exception is java.lang.NoSuchMethodError: com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.<init>(Lcom/google/gson/internal/ConstructorConstructor;Lcom/google/gson/FieldNamingStrategy;Lcom/google/gson/internal/Excluder;)V
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:189) ~[spring-beans-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:588) ~[spring-beans-4.3.2.RELEASE.jar:4.3.2.RELEASE]
... 37 common frames omitted
Caused by: java.lang.NoSuchMethodError: com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.<init>(Lcom/google/gson/internal/ConstructorConstructor;Lcom/google/gson/FieldNamingStrategy;Lcom/google/gson/internal/Excluder;)V
at org.jclouds.json.internal.DeserializationConstructorAndReflectiveTypeAdapterFactory.<init>(DeserializationConstructorAndReflectiveTypeAdapterFactory.java:116) ~[jclouds-core-1.9.2.jar:1.9.2]
at org.jclouds.json.config.GsonModule.provideGson(GsonModule.java:129) ~[jclouds-core-1.9.2.jar:1.9.2]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_25]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_25]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_25]
at java.lang.reflect.Method.invoke(Method.java:483) ~[na:1.8.0_25]
at com.google.inject.internal.ProviderMethod.get(ProviderMethod.java:104) ~[guice-3.0.jar:na]
at com.google.inject.internal.InternalFactoryToProviderAdapter.get(InternalFactoryToProviderAdapter.java:40) ~[guice-3.0.jar:na]
at com.google.inject.internal.ProviderToInternalFactoryAdapter$1.call(ProviderToInternalFactoryAdapter.java:46) ~[guice-3.0.jar:na]
at com.google.inject.internal.InjectorImpl.callInContext(InjectorImpl.java:1031) ~[guice-3.0.jar:na]
at com.google.inject.internal.ProviderToInternalFactoryAdapter.get(ProviderToInternalFactoryAdapter.java:40) ~[guice-3.0.jar:na]
at com.google.inject.Scopes$1$1.get(Scopes.java:65) ~[guice-3.0.jar:na]
at com.google.inject.internal.InternalFactoryToProviderAdapter.get(InternalFactoryToProviderAdapter.java:40) ~[guice-3.0.jar:na]
at com.google.inject.internal.SingleParameterInjector.inject(SingleParameterInjector.java:38) ~[guice-3.0.jar:na]
at com.google.inject.internal.SingleParameterInjector.getAll(SingleParameterInjector.java:62) ~[guice-3.0.jar:na]
at com.google.inject.internal.ConstructorInjector.construct(ConstructorInjector.java:84) ~[guice-3.0.jar:na]
at com.google.inject.internal.ConstructorBindingImpl$Factory.get(ConstructorBindingImpl.java:254) ~[guice-3.0.jar:na]
at com.google.inject.internal.ProviderToInternalFactoryAdapter$1.call(ProviderToInternalFactoryAdapter.java:46) ~[guice-3.0.jar:na]
at com.google.inject.internal.InjectorImpl.callInContext(InjectorImpl.java:1031) ~[guice-3.0.jar:na]
at com.google.inject.internal.ProviderToInternalFactoryAdapter.get(ProviderToInternalFactoryAdapter.java:40) ~[guice-3.0.jar:na]
at com.google.inject.Scopes$1$1.get(Scopes.java:65) ~[guice-3.0.jar:na]
at com.google.inject.internal.InternalFactoryToProviderAdapter.get(InternalFactoryToProviderAdapter.java:40) ~[guice-3.0.jar:na]
at com.google.inject.internal.FactoryProxy.get(FactoryProxy.java:54) ~[guice-3.0.jar:na]
at com.google.inject.internal.InternalInjectorCreator$1.call(InternalInjectorCreator.java:204) ~[guice-3.0.jar:na]
at com.google.inject.internal.InternalInjectorCreator$1.call(InternalInjectorCreator.java:198) ~[guice-3.0.jar:na]
at com.google.inject.internal.InjectorImpl.callInContext(InjectorImpl.java:1024) ~[guice-3.0.jar:na]
at com.google.inject.internal.InternalInjectorCreator.loadEagerSingletons(InternalInjectorCreator.java:198) ~[guice-3.0.jar:na]
at com.google.inject.internal.InternalInjectorCreator.injectDynamically(InternalInjectorCreator.java:179) ~[guice-3.0.jar:na]
at com.google.inject.internal.InternalInjectorCreator.build(InternalInjectorCreator.java:109) ~[guice-3.0.jar:na]
at com.google.inject.Guice.createInjector(Guice.java:95) ~[guice-3.0.jar:na]
at org.jclouds.ContextBuilder.buildInjector(ContextBuilder.java:402) ~[jclouds-core-1.9.2.jar:1.9.2]
at org.jclouds.ContextBuilder.buildInjector(ContextBuilder.java:326) ~[jclouds-core-1.9.2.jar:1.9.2]
at org.jclouds.ContextBuilder.buildApi(ContextBuilder.java:644) ~[jclouds-core-1.9.2.jar:1.9.2]
at org.jclouds.ContextBuilder.buildApi(ContextBuilder.java:636) ~[jclouds-core-1.9.2.jar:1.9.2]
at com.appapi.helpers.WebStorage.<init>(WebStorage.java:49) ~[classes/:na]
at com.appapi.config.AppConfiguration.storage(AppConfiguration.java:41) ~[classes/:na]
at com.appapi.config.AppConfiguration$$EnhancerBySpringCGLIB$$d004a038.CGLIB$storage$2(<generated>) ~[classes/:na]
at com.appapi.config.AppConfiguration$$EnhancerBySpringCGLIB$$d004a038$$FastClassBySpringCGLIB$$59b0bc24.invoke(<generated>) ~[classes/:na]
at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228) ~[spring-core-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:356) ~[spring-context-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at com.appapi.config.AppConfiguration$$EnhancerBySpringCGLIB$$d004a038.storage(<generated>) ~[classes/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_25]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_25]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_25]
at java.lang.reflect.Method.invoke(Method.java:483) ~[na:1.8.0_25]
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:162) ~[spring-beans-4.3.2.RELEASE.jar:4.3.2.RELEASE]
... 38 common frames omitted
我在我的 pom 文件中包含了 jclouds 1.9.2 版;
<dependency>
<groupId>org.apache.jclouds</groupId>
<artifactId>jclouds-all</artifactId>
<version>1.9.2</version>
</dependency>
有人能告诉我为什么我会收到未找到课程的错误吗?我的 POM 中没有包含任何 Google 依赖项,因此任何可用的依赖项都包含在我的依赖项之一中。
【问题讨论】:
可以分享mvn dependency:tree
输出
检查您正在使用的 jClouds 版本。可能是您引用了项目中指定的版本中不可用的方法。
【参考方案1】:
这是 jclouds 中的一个已知问题。请参阅 JCLOUDS-1160 和 JCLOUDS-1166。在解决这些问题之前,如果您无法强制使用 Gson
另一个选择是使用maven-shade-plugin
来遮蔽 jclouds 依赖项并将 Gson 捆绑在其中。这样你应该可以使用你的环境需要的 Gson 版本,而 jclouds 使用阴影版本。
【讨论】:
感谢您的评论。我将如何使用 maven-shade-plugin 来解决这个问题?抱歉,我之前没有使用过 shade-plugin。 看看jclouds Jenkins plugin。它基本上定义了一个模块 jclouds-shaded,它具有 jclouds 依赖项并配置 maven-shade-plugin 以生成一个带有 jclouds 和冲突依赖项的 uber jar。它们遮蔽 Guava/Guice,但在您的情况下,您只想遮蔽 Gson。他们还配置包重定位以避免包与“外部”依赖项发生冲突(您也应该使用 Gson)。 最后,在你的项目中,你只需要依赖刚刚创建的“jclouds-shaded”jar,而不是依赖于 jclouds。它将包含所需的一切。 谢谢,我会尝试一下。有谁知道 jclouds 本身解决问题可能需要多长时间? 不幸的是,该修复没有预计到达时间。您可能想在此处关注讨论:markmail.org/message/zqsj5ao4fjvalcoh【参考方案2】:我一开始很难使用 shaded 插件创建 ubar jar,但最终让它工作。对于其他可能像我一样挣扎的人。
首先,创建一个新的(空的)maven 项目。
这是我的 POM 文件,其中包含 apache jclouds 一个旧版本的 Gson,并重命名了 Gson 包以在最终 jar 中使用,因此它不会与我的主项目中的 Gson 冲突(请参阅 POM 文件的重定位部分) .
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>digital.sheppard</groupId>
<artifactId>jclouds-shaded</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.4</version>
</dependency>
<dependency>
<groupId>org.apache.jclouds</groupId>
<artifactId>jclouds-all</artifactId>
<version>1.9.2</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.4.3</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<relocations>
<relocation>
<pattern>com.google.code.gson</pattern>
<shadedPattern>com.shaded.code.gson</shadedPattern>
</relocation>
</relocations>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
在终端,构建项目以创建 jar 文件。
mvn package
最后,将 jar 文件复制到主项目的根目录中,在我的例子中是一个 Spring Boot Web 应用程序。
在你的项目的根目录下创建一个名为'maven-local-repo'的文件夹,然后在终端执行以下命令将你新创建的shaded jar文件安装到你项目的本地存储库中(显然改变文件名, artifact 等以匹配您创建的阴影 jar)。
mvn deploy:deploy-file -DgroupId=digital.sheppard -DartifactId=jclouds-shaded -Dversion=1.0-SNAPSHOT -Durl=file:./local-maven-repo/ -DrepositoryId=local-maven-repo -DupdateReleaseInfo=true -Dfile=jclouds-shaded-1.0-SNAPSHOT.jar
将您的本地存储库添加到您的 POM 文件中;
<repositories>
<repository>
<id>local-maven-repo</id>
<url>file:///$project.basedir/local-maven-repo</url>
</repository>
</repositories>
最后添加一个依赖;
<dependency>
<groupId>digital.sheppard</groupId>
<artifactId>jclouds-shaded</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
对我来说,这就像一个魅力。
【讨论】:
不错!对我来说,用<artifactId>jclouds-core</artifactId>
构建阴影罐就足够了
我就把它留在这里 - bintray.com/rocketraccoon/jclouds-shaded-gson-repo/…【参考方案3】:
我将我的 Java 代码切换为使用他们的原始 HTTP API:
https://support.rackspace.com/how-to/cloud-files-curl-cookbook/
例如
public class CloudFilesClient
private final String username;
private final String apiKey;
private final RestTemplate rest = new RestTemplate();
private static final String AUTH_URL = "https://auth.api.rackspacecloud.com/v1.1/auth";
private static final String AUTH_DOCUMENT = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
"<credentials xmlns=\"http://docs.rackspacecloud.com/auth/api/v1.1\" " +
" username=\"%s\" " +
" key=\"%s\" />";
private CloudFilesClient (String aUsername, String aApiKey)
username = aUsername;
apiKey = aApiKey;
public List<Map<String,Object>> listObjects (String aRegionName, String aContainerName)
Map<String, Object> auth = auth();
Map<String, Object> cloudFiles = cloudFiles(auth, aRegionName);
HttpHeaders headers = new HttpHeaders();
headers.set("X-Auth-Token", token(auth));
HttpEntity<?> e = new HttpEntity<>(headers);
ResponseEntity<List> exchange = rest.exchange(((String)cloudFiles.get("publicURL"))+"/"+aContainerName, HttpMethod.GET, e, List.class);
return exchange.getBody();
public Map<String,Object> putObject (String aRegionName, String aContainerName, String aObjectName, String aLocalFilePath) throws IOException
Map<String, Object> auth = auth();
Map<String, Object> cloudFiles = cloudFiles(auth, aRegionName);
String token = token(auth);
File file = new File(aLocalFilePath);
Assert.isTrue(file.exists(),"File not found: " + aLocalFilePath);
HttpHeaders headers = new HttpHeaders();
headers.set("X-Auth-Token", token);
headers.setContentType(MediaType.valueOf(Files.probeContentType(file.toPath())));
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
HttpEntity<Resource> requestEntity = new HttpEntity<>(new FileSystemResource(file), headers);
ResponseEntity<Map> result = rest.exchange(((String)cloudFiles.get("publicURL"))+"/"+aContainerName+"/"+aObjectName, HttpMethod.PUT, requestEntity,Map.class);
return result.getBody();
public String getTemporaryUrl (String aRegionName, String aContainerName, String aObjectName) throws URISyntaxException
String key = UUID.randomUUID().toString();
Map<String, Object> auth = auth();
Map<String, Object> cloudFiles = cloudFiles(auth, aRegionName);
HttpHeaders headers = new HttpHeaders();
headers.set("X-Auth-Token", token(auth));
headers.set("X-Account-Meta-Temp-Url-Key", key);
HttpEntity<?> e = new HttpEntity<>(headers);
rest.exchange(((String)cloudFiles.get("publicURL")), HttpMethod.POST, e, List.class);
String method = "GET";
long expires = System.currentTimeMillis()/1000+3600;
URI endpoint = (new URI((String)cloudFiles.get("publicURL")));
String base = endpoint.getScheme()+"://"+endpoint.getHost();
String path = endpoint.getPath()+"/"+aContainerName+"/"+aObjectName;
String hmacBody = String.format("%s\n%s\n%s", method,expires,path);
String sig = HmacUtils.hmacSha1Hex(key, hmacBody);
return String.format("%s%s?temp_url_sig=%s&temp_url_expires=%s",base, path, sig, expires);
private Map<String,Object> auth ()
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_XML);
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
HttpEntity<String> requestEntity = new HttpEntity<>(String.format(AUTH_DOCUMENT,username,apiKey), headers);
ResponseEntity<Map> result = rest.exchange(AUTH_URL, HttpMethod.POST, requestEntity, Map.class);
Map<String,Object> body = result.getBody();
return (Map<String, Object>) body.get("auth");
private Map<String, Object> cloudFiles (Map<String,Object> aAuth, String aRegionName)
Map<String, Object> catalog = (Map<String, Object>) aAuth.get("serviceCatalog");
List<Map<String, Object>> cloudFiles = (List<Map<String, Object>>) catalog.get("cloudFiles");
Optional<Map<String, Object>> region = cloudFiles.stream().filter(r->r.get("region").equals(aRegionName)).findFirst();
Assert.isTrue(region.isPresent(),"Unknown region: " + aRegionName);
return region.get();
private String token (Map<String,Object> aAuth)
Map<String, Object> token = (Map<String, Object>) aAuth.get("token");
return (String)token.get("id");
public static CloudFilesClient build (String aUsername, String aApiKey)
return new CloudFilesClient(aUsername, aApiKey);
【讨论】:
【参考方案4】:我对 gradle、SpringBoot 或 JClouds 几乎一无所知...
排除了这些免责声明,我像这样破解了我的 gradle 构建文件:
dependencies
...
// REQUIRED TO ALLOW JCLOUDS AND GSON TO PLAY NICELY.... XXX
compile 'com.google.code.gson:gson:2.5'
...
这似乎具有将 GSON 版本锁定为 2.5 的效果,这是适用于 JClouds 和 SpringBoot 的最新版本。有了这个 hack,我就可以构建和运行我的应用程序了。
【讨论】:
这似乎不适用于当前版本的 Spring Boot,因为它似乎依赖于 2.5 之后引入的 gson 功能。特别是2.5好像没有com.google.gson.GsonBuilder.setLenient()Lcom/google/gson/GsonBuilder;
以上是关于在 Spring Boot 应用程序中使用 Rackspace 时出现 Apache jclouds java.lang.NoSuchMethodError的主要内容,如果未能解决你的问题,请参考以下文章
在 Spring Boot 中,啥告诉应用程序使用数据库? [复制]
有没有办法在 Spring Boot 应用程序配置中使用 Spring Cloud cipher?
Spring Boot2:使用Spring Boot结合Thymeleaf模板引擎使用总结