簡體   English   中英

Apache jclouds java.lang.NoSuchMethodError 在 Spring 啟動應用程序中使用 Rackspace 時

[英]Apache jclouds java.lang.NoSuchMethodError when using Rackspace in a Spring Boot application

我正在嘗試將 Apache Jclouds 集成到我正在處理的 Spring Boot 應用程序中,以便我可以將文件上傳到 Rackspace Cloud Files(UK)。

我創建了一個 class 作為 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 時會生成 class not found 錯誤。

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 文件中包含了 1.9.2 版的 jclouds;

<dependency>
            <groupId>org.apache.jclouds</groupId>
            <artifactId>jclouds-all</artifactId>
            <version>1.9.2</version>
        </dependency>

有人能告訴我為什么我收到 class not found 錯誤嗎? 我沒有在我的 POM 中包含任何 Google 依賴項,因此任何可用的都包含在我的一個依賴項中。

這是jclouds中的一個已知問題。 JCLOUDS-1160JCLOUDS-1166 在修復這些問題之前,如果你不能強制使用Gson <= 2.5的版本,那么你將無法使用Spring Boot的jclouds。

另一個選擇是使用maven-shade-plugin來遮蔽jclouds依賴關系並將Gson捆綁在其中。 這樣你就可以使用你的環境需要的Gson版本,而jclouds使用着色版本。

我最初使用着色插件努力創建ubar jar,最終讓它運行起來。 對於任何可能像我一樣掙扎的人。

首先,創建一個新的(空)maven項目。

這是我的POM文件,其中包括apache jclouds舊版本的Gson,並重命名為最終jar中使用的Gson包,因此它與我的主項目中的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”的文件夾,並在終端執行以下命令將新創建的着色jar文件安裝到項目的本地存儲庫中(顯然將文件名,工件等更改為匹配你創建的陰影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>

對我而言,就像一個魅力。

我將我的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);
  }

}

我幾乎不了解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的效果,這是適用於JCloud和SpringBoot的最新版本。 有了這個hack,我可以構建並運行我的應用程序。

對於那些在 2023 年初偶然發現這個問題的人,我的 jcloud 版本是 2.5.0,我通過強制 gradle 使用 Gson 2.8.9 解決了這個問題。

configurations {
    all {
        resolutionStrategy {
            force 'com.google.code.gson:gson:2.8.9'
        }
    }
}

查看較新的 jcloud 版本的發行說明,了解最后支持的 GSON 版本是什么,並嘗試使用它。 有時 Guava 也會導致與 Spring 的兼容性問題。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM