2

I am using Intellij and Maven for my GAE Java project. I have some strange issues with calling createOrReplace from GcsService in Google Cloud Storage, that is dependent on me editing a single file in my project. Here is what happens:

I have a stable revision on Github. I checkout that revision and use an intellij configuration to deploy the app. My deployment looks like this: enter image description here After the clean install and build, this is the command that gets executed: /Library/Java/JavaVirtualMachines/jdk1.7.0_25.jdk/Contents/Home/bin/java -Dfile.encoding=UTF-8 -classpath /Users/me/.m2/repository/com/google/appengine/appengine-java-sdk/1.9.15/appengine-java-sdk/appengine-java-sdk-1.9.15/lib/appengine-tools-api.jar com.google.appengine.tools.admin.AppCfg --email=me@gmail.com --passin --no_cookies update /Users/me/git/blunka/harry-gcp/module-ear/target/module-ear-1.0

I then add a comment to a specific source file. I redeploy and I notice a bunch of output files under /target have changed. My app is now broken with this error:

java.lang.NoSuchMethodError: com.google.common.base.Stopwatch.createUnstarted()Lcom/google/common/base/Stopwatch;
    at com.google.appengine.tools.cloudstorage.RetryHelper.runWithRetries(RetryHelper.java:156)
    at com.google.appengine.tools.cloudstorage.GcsServiceImpl.createOrReplace(GcsServiceImpl.java:70)

I now delete that comment and deploy again. I do a git status and notice that some of the changed files under /target are no longer there. My app works fine again.

When I look at the decompiled .class files of the modified class, they are identical. Here is my dep tree for the module that is throwing the error:

[INFO] +- com.google.api-client:google-api-client-appengine:jar:1.19.0:compile
[INFO] |  \- com.google.api-client:google-api-client:jar:1.19.0:compile
[INFO] |     \- com.google.guava:guava-jdk5:jar:13.0:compile
[INFO] +- com.google.appengine.tools:appengine-gcs-client:jar:RELEASE:compile
[INFO] |  \- (com.google.guava:guava:jar:18.0:compile - omitted for duplicate)
[INFO] +- com.google.guava:guava:jar:18.0:compile
[INFO] \- com.googlecode.objectify:objectify:jar:5.1.1:compile
[INFO]    \- (com.google.guava:guava:jar:17.0:compile - omitted for conflict with 18.0)

I have a few questions:

  1. Why does a comment cause my output files to change?
  2. Why do changed output files from a comment cause a change in behavior of the app, even though the decompiled source is the same?
  3. If guava (google.common.base) has collisions, how can I fix them?
  4. How can I prevent something like this from happening in the future?
clocksmith
  • 6,226
  • 3
  • 32
  • 45
  • Perhaps your app was deployed to an node that had an old version of guava on its classpath, so a redeploy landed you on another machine. The solution is to [shade](https://maven.apache.org/plugins/maven-shade-plugin/) your dependencies to avoid conflicts. As a platform, it's Google who should do that and not you as a developer. – Ben Manes Mar 20 '15 at 02:07
  • Interesting. That would be awful, but I'll try deploying the same "working" build over and over and see if eventually it fails. – clocksmith Mar 20 '15 at 04:34
  • @BenManes I tried 10 deploys without changing anything, and they all worked. As soon as I edited a single specific class, I guess maven detects a change and a `git status` shows that output files for that class have been modified. I redeploy and it is now broken. I do not think it has to do with specific app engine nodes. I believe it is a very strange problem with my build. Eventually, I will shade, but I want to first figure out the underlying problem. Thanks. – clocksmith Mar 20 '15 at 21:57
  • 1
    Look at what version of guava is in your `war` file. You can use `mvn dependency:tree -Dverbose -Dincludes=com.google.guava` to see where it is coming from – Ben Manes Mar 20 '15 at 22:14
  • You might also want to explode your dependencies and see if its improperly bundled in a jar (e.g. JUnit's Hamcrest) causing the wrong class to be resolved. – Ben Manes Mar 20 '15 at 22:17
  • I posted my dep tree in the original post. How can I explode my dependencies? – clocksmith Mar 20 '15 at 22:21
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/73448/discussion-between-clocksmith-and-ben-manes). – clocksmith Mar 20 '15 at 22:35
  • 1
    Oh! Its due to `com.google.guava:guava-jdk5:jar:13.0` which is a **different** artifact id than `guava`. This causes both 18 and 13 to be on the classpath in unpredictable order. You need to exclude this dependency. – Ben Manes Mar 20 '15 at 23:27

1 Answers1

4

Sorry for "stealing" the answer, but @ben-manes is right in his comment. I had the same problem and his last message helped me. I just want to make this as an answer, because not everybody looks through comments.

google-api-client depends on guava-jdk5, which creates a conflict with guava-18+, used by appengine-gcs-client

<dependency>
    <groupId>com.google.api-client</groupId>
    <artifactId>google-api-client-appengine</artifactId>
    <version>1.20.0</version>
    <exclusions>
        <!-- creates conflicts with another guava version in appengine-gcs-client -->
        <exclusion>
            <groupId>com.google.guava</groupId>
            <artifactId>guava-jdk5</artifactId>
        </exclusion>
    </exclusions>
</dependency>
alex.dorokhov
  • 1,218
  • 12
  • 17