You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by br...@apache.org on 2019/01/15 10:20:26 UTC

svn commit: r1851333 - in /subversion/trunk/subversion/bindings/javahl: native/ src/org/apache/subversion/javahl/ src/org/apache/subversion/javahl/callback/ tests/org/apache/subversion/javahl/

Author: brane
Date: Tue Jan 15 10:20:26 2019
New Revision: 1851333

URL: http://svn.apache.org/viewvc?rev=1851333&view=rev
Log:
Fix issue #4801: Make JavaHL blame return byte[] file contents in the
blame callback instead of assuming they can be converted to String.

[in subversion/bindings/javahl/src/org/apache/subversion/javahl]
* ISVNClient.java
  (ISVNClient.blame): Add a new overload that uses the new BlameLineCallback.
   Deprecate the other two overloads that use BlameCallback.
* SVNClient.java
  (SVNClient.blame): Implement new native overload and deprecate the old ones.
  (SVNClient.BlameCallbackAdapter): New helper class.

* callback/BlameCallback.java
  (BlameCallback): Deprecated.
* callback/BlameLineCallback.java
  (BlameLineCallback): New, replaces BlameCallback.

[in subversion/bindings/javahl/tests/org/apache/subversion/javahl]
* BasicTests.java
  (testBasicBlame, testBlameWithDiffOptions): Suppress deprecation warnings
   as these tests use the old API, and should continue to do so in order to
   test the callback adapter.
  (testBinaryBlame): New test case.
  (collectBlameLines, BlameCallbackImpl): Suppress deprecation warnings.
  (BlameLineCallbackImpl): New helper class.
* ExceptionTests.java
  (testBlameCallback): Use the new API in this test case.

[in subversion/bindings/javahl/native]
* org_apache_subversion_javahl_SVNClient.cpp
  (Java_org_apache_subversion_javahl_SVNClient_blame): Update parameter order.
* BlameCallback.cpp
  (BlameCallback::singleLine): Use BlameLineCallback instead of BlameCallback.

Added:
    subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/callback/BlameLineCallback.java   (with props)
Modified:
    subversion/trunk/subversion/bindings/javahl/native/BlameCallback.cpp
    subversion/trunk/subversion/bindings/javahl/native/org_apache_subversion_javahl_SVNClient.cpp
    subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/ISVNClient.java
    subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/SVNClient.java
    subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/callback/BlameCallback.java
    subversion/trunk/subversion/bindings/javahl/tests/org/apache/subversion/javahl/BasicTests.java
    subversion/trunk/subversion/bindings/javahl/tests/org/apache/subversion/javahl/ExceptionTests.java

Modified: subversion/trunk/subversion/bindings/javahl/native/BlameCallback.cpp
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/bindings/javahl/native/BlameCallback.cpp?rev=1851333&r1=1851332&r2=1851333&view=diff
==============================================================================
--- subversion/trunk/subversion/bindings/javahl/native/BlameCallback.cpp (original)
+++ subversion/trunk/subversion/bindings/javahl/native/BlameCallback.cpp Tue Jan 15 10:20:26 2019
@@ -89,13 +89,13 @@ BlameCallback::singleLine(apr_int64_t li
   static jmethodID mid = 0;
   if (mid == 0)
     {
-      jclass clazz = env->FindClass(JAVAHL_CLASS("/callback/BlameCallback"));
+      jclass clazz = env->FindClass(JAVAHL_CLASS("/callback/BlameLineCallback"));
       if (JNIUtil::isJavaExceptionThrown())
         POP_AND_RETURN(SVN_NO_ERROR);
 
       mid = env->GetMethodID(clazz, "singleLine",
                              "(JJLjava/util/Map;JLjava/util/Map;"
-                             "Ljava/lang/String;Ljava/lang/String;Z)V");
+                             "Ljava/lang/String;Z[B)V");
       if (JNIUtil::isJavaExceptionThrown() || mid == 0)
         POP_AND_RETURN(SVN_NO_ERROR);
     }
@@ -117,14 +117,14 @@ BlameCallback::singleLine(apr_int64_t li
   if (JNIUtil::isJavaExceptionThrown())
     POP_AND_RETURN(SVN_NO_ERROR);
 
-  jstring jline = JNIUtil::makeJString(line->data);
+  jbyteArray jline = JNIUtil::makeJByteArray(line);
   if (JNIUtil::isJavaExceptionThrown())
     POP_AND_RETURN(SVN_NO_ERROR);
 
   // call the Java method
   env->CallVoidMethod(m_callback, mid, (jlong)line_no, (jlong)revision,
                       jrevProps, (jlong)mergedRevision, jmergedRevProps,
-                      jmergedPath, jline, (jboolean)localChange);
+                      jmergedPath, (jboolean)localChange, jline);
 
   POP_AND_RETURN_EXCEPTION_AS_SVNERROR();
 }

Modified: subversion/trunk/subversion/bindings/javahl/native/org_apache_subversion_javahl_SVNClient.cpp
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/bindings/javahl/native/org_apache_subversion_javahl_SVNClient.cpp?rev=1851333&r1=1851332&r2=1851333&view=diff
==============================================================================
--- subversion/trunk/subversion/bindings/javahl/native/org_apache_subversion_javahl_SVNClient.cpp (original)
+++ subversion/trunk/subversion/bindings/javahl/native/org_apache_subversion_javahl_SVNClient.cpp Tue Jan 15 10:20:26 2019
@@ -1658,8 +1658,8 @@ JNIEXPORT void JNICALL
 Java_org_apache_subversion_javahl_SVNClient_blame
 (JNIEnv *env, jobject jthis, jstring jpath, jobject jpegRevision,
  jobject jrevisionStart, jobject jrevisionEnd, jboolean jignoreMimeType,
- jboolean jincludeMergedRevisions, jobject jblameCallback,
- jobject jdiffOptions)
+ jboolean jincludeMergedRevisions, jobject jdiffOptions,
+ jobject jblameCallback)
 {
   JNIEntry(SVNClient, blame);
   SVNClient *cl = SVNClient::getCppObject(jthis);

Modified: subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/ISVNClient.java
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/ISVNClient.java?rev=1851333&r1=1851332&r2=1851333&view=diff
==============================================================================
--- subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/ISVNClient.java (original)
+++ subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/ISVNClient.java Tue Jan 15 10:20:26 2019
@@ -1394,17 +1394,34 @@ public interface ISVNClient
      * @param ignoreMimeType whether or not to ignore the mime-type
      * @param includeMergedRevisions whether or not to include extra merge
      *                      information
+     * @param options       additional options for controlling the output
      * @param callback      callback to receive the file content and the other
      *                      information
-     * @param options       additional options for controlling the output
      * @throws ClientException
-     * @since 1.9
+     * @since 1.12
+     */
+    void blame(String path, Revision pegRevision, Revision revisionStart,
+               Revision revisionEnd, boolean ignoreMimeType,
+               boolean includeMergedRevisions,
+               DiffOptions options, BlameLineCallback callback)
+        throws ClientException;
+
+    /**
+     * Retrieve the content together with the author, the revision and the date
+     * of the last change of each line
+     * <p>
+     * Behaves like the 1.12 version but uses BlameCallback instead of
+     * BlameLineCallback. The former expects that file contents can be
+     * converted from UTF-8 to a String, which is not true in general
+     * and may throw exceptions.
+     * @deprecated Use the 1.12 version with BlameLineCallback
      */
+    @Deprecated
     void blame(String path, Revision pegRevision, Revision revisionStart,
                Revision revisionEnd, boolean ignoreMimeType,
                boolean includeMergedRevisions,
                BlameCallback callback, DiffOptions options)
-            throws ClientException;
+        throws ClientException;
 
     /**
      * Retrieve the content together with the author, the revision and the date
@@ -1412,12 +1429,14 @@ public interface ISVNClient
      * <p>
      * Behaves like the 1.9 version with <code>options</code> set to
      * their default values.
+     * @deprecated Use the 1.12 version with BlameLineCallback
      */
+    @Deprecated
     void blame(String path, Revision pegRevision, Revision revisionStart,
                Revision revisionEnd, boolean ignoreMimeType,
                boolean includeMergedRevisions,
                BlameCallback callback)
-            throws ClientException;
+        throws ClientException;
 
     /**
      * Set directory for the configuration information, taking the

Modified: subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/SVNClient.java
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/SVNClient.java?rev=1851333&r1=1851332&r2=1851333&view=diff
==============================================================================
--- subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/SVNClient.java (original)
+++ subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/SVNClient.java Tue Jan 15 10:20:26 2019
@@ -30,6 +30,7 @@ import java.io.OutputStream;
 import java.io.FileOutputStream;
 import java.io.FileNotFoundException;
 import java.io.ByteArrayOutputStream;
+import java.io.UnsupportedEncodingException;
 
 import java.util.Collection;
 import java.util.Collections;
@@ -705,6 +706,7 @@ public class SVNClient implements ISVNCl
                                 boolean ignoreExternals)
             throws ClientException;
 
+    @Deprecated
     public void blame(String path, Revision pegRevision,
                       Revision revisionStart,
                       Revision revisionEnd, boolean ignoreMimeType,
@@ -716,13 +718,27 @@ public class SVNClient implements ISVNCl
               includeMergedRevisions, callback, null);
     }
 
+    @Deprecated
+    public void blame(String path, Revision pegRevision,
+                      Revision revisionStart,
+                      Revision revisionEnd, boolean ignoreMimeType,
+                      boolean includeMergedRevisions,
+                      BlameCallback callback,
+                      DiffOptions options)
+            throws ClientException
+    {
+        blame(path, pegRevision, revisionStart, revisionEnd,
+              ignoreMimeType, includeMergedRevisions, options,
+              new BlameCallbackAdapter(callback));
+    }
+
     public native void blame(String path, Revision pegRevision,
                              Revision revisionStart,
                              Revision revisionEnd, boolean ignoreMimeType,
                              boolean includeMergedRevisions,
-                             BlameCallback callback,
-                             DiffOptions options)
-            throws ClientException;
+                             DiffOptions options,
+                             BlameLineCallback callback)
+        throws ClientException;
 
     public native void setConfigDirectory(String configDir)
             throws ClientException;
@@ -897,4 +913,42 @@ public class SVNClient implements ISVNCl
                                           null);
         }
     }
+
+    /**
+     * A private class that adapts from BlameLineCallback to BlameCallback.
+     */
+    @Deprecated
+    private class BlameCallbackAdapter implements BlameLineCallback
+    {
+        private BlameCallback wrappedCallback = null;
+
+        public BlameCallbackAdapter(BlameCallback callback)
+        {
+            wrappedCallback = callback;
+        }
+
+        // Implementation of BlameLineCallback
+        public void singleLine(long lineNum, long revision,
+                               Map<String, byte[]> revProps, long mergedRevision,
+                               Map<String, byte[]> mergedRevProps,
+                               String mergedPath, boolean localChange,
+                               byte[] line)
+            throws ClientException
+        {
+            if (wrappedCallback == null)
+                return;
+
+            String convertedLine = null;
+            try {
+                convertedLine = new String(line, "UTF-8");
+            }
+            catch (UnsupportedEncodingException ex) {
+                throw ClientException.fromException(ex);
+            }
+
+            wrappedCallback.singleLine(lineNum, revision,
+                                       revProps, mergedRevision, mergedRevProps,
+                                       mergedPath, convertedLine, localChange);
+        }
+    }
 }

Modified: subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/callback/BlameCallback.java
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/callback/BlameCallback.java?rev=1851333&r1=1851332&r2=1851333&view=diff
==============================================================================
--- subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/callback/BlameCallback.java (original)
+++ subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/callback/BlameCallback.java Tue Jan 15 10:20:26 2019
@@ -31,7 +31,9 @@ import org.apache.subversion.javahl.ISVN
 /**
  * This interface is used to receive every single line for a file on a
  * the {@link ISVNClient#blame} call.
+ * @deprecated use {@link BlameLineCallback} instead.
  */
+@Deprecated
 public interface BlameCallback
 {
     /**

Added: subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/callback/BlameLineCallback.java
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/callback/BlameLineCallback.java?rev=1851333&view=auto
==============================================================================
--- subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/callback/BlameLineCallback.java (added)
+++ subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/callback/BlameLineCallback.java Tue Jan 15 10:20:26 2019
@@ -0,0 +1,56 @@
+/**
+ * @copyright
+ * ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you under the Apache License, Version 2.0 (the
+ *    "License"); you may not use this file except in compliance
+ *    with the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing,
+ *    software distributed under the License is distributed on an
+ *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *    KIND, either express or implied.  See the License for the
+ *    specific language governing permissions and limitations
+ *    under the License.
+ * ====================================================================
+ * @endcopyright
+ */
+
+package org.apache.subversion.javahl.callback;
+
+import org.apache.subversion.javahl.ClientException;
+
+import java.util.Map;
+import org.apache.subversion.javahl.ISVNClient;
+
+/**
+ * This interface is used to receive every single line for a file on a
+ * the {@link ISVNClient#blame} call.
+ * @since 1.12
+ */
+public interface BlameLineCallback
+{
+    /**
+     * the method will be called for every line in a file.
+     * @param lineNum           the line number for this line
+     * @param revision          the revision of the last change.
+     * @param revProps          the revision properties for this revision.
+     * @param mergedRevision    the revision of the last merged change.
+     * @param mergedRevProps    the revision properties for the last merged
+     *                          change.
+     * @param mergedPath        the path of the last merged change.
+     * @param localChange       true if the line was locally modified.
+     * @param line              the line in the file.
+     */
+    public void singleLine(long lineNum, long revision,
+                           Map<String, byte[]> revProps, long mergedRevision,
+                           Map<String, byte[]> mergedRevProps,
+                           String mergedPath, boolean localChange,
+                           byte[] line)
+        throws ClientException;
+}

Propchange: subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/callback/BlameLineCallback.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: subversion/trunk/subversion/bindings/javahl/tests/org/apache/subversion/javahl/BasicTests.java
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/bindings/javahl/tests/org/apache/subversion/javahl/BasicTests.java?rev=1851333&r1=1851332&r2=1851333&view=diff
==============================================================================
--- subversion/trunk/subversion/bindings/javahl/tests/org/apache/subversion/javahl/BasicTests.java (original)
+++ subversion/trunk/subversion/bindings/javahl/tests/org/apache/subversion/javahl/BasicTests.java Tue Jan 15 10:20:26 2019
@@ -22,6 +22,8 @@
  */
 package org.apache.subversion.javahl;
 
+import static org.junit.Assert.*;
+
 import org.apache.subversion.javahl.callback.*;
 import org.apache.subversion.javahl.types.*;
 
@@ -4093,6 +4095,7 @@ public class BasicTests extends SVNTests
      * @throws Throwable
      * @since 1.5
      */
+    @SuppressWarnings("deprecation")
     public void testBasicBlame() throws Throwable
     {
         OneTest thisTest = new OneTest();
@@ -4122,6 +4125,7 @@ public class BasicTests extends SVNTests
      * Test blame with diff options.
      * @since 1.9
      */
+    @SuppressWarnings("deprecation")
     public void testBlameWithDiffOptions() throws Throwable
     {
         OneTest thisTest = new OneTest();
@@ -4155,6 +4159,46 @@ public class BasicTests extends SVNTests
     }
 
     /**
+     * Test the new 1.12 blame interface on a file with null bytes.
+     * @throws Throwable
+     * @since 1.12
+     */
+    public void testBinaryBlame() throws Throwable
+    {
+        final byte[] lineIn = {0x0, 0x0, 0x0, 0xa};
+        final byte[] lineOut = {0x0, 0x0, 0x0};
+
+        OneTest thisTest = new OneTest();
+        // Modify the file iota, adding null bytes.
+        File iota = new File(thisTest.getWorkingCopy(), "iota");
+        FileOutputStream stream = new FileOutputStream(iota, false);
+        stream.write(lineIn);
+        stream.close();
+        Set<String> srcPaths = new HashSet<String>(1);
+        srcPaths.add(thisTest.getWCPath());
+        try {
+            client.username("rayjandom");
+            client.commit(srcPaths, Depth.infinity, false, false, null, null,
+                          new ConstMsg("NUL bytes written to /iota"), null);
+        } finally {
+            client.username("jrandom");
+        }
+
+        // Test the current interface
+        BlameLineCallbackImpl callback = new BlameLineCallbackImpl();
+        client.blame(thisTest.getWCPath() + "/iota", Revision.HEAD,
+                     Revision.getInstance(0), Revision.HEAD,
+                     false, false, null, callback);
+        assertEquals(1, callback.numberOfLines());
+
+        BlameLineCallbackImpl.BlameLine line = callback.getBlameLine(0);
+        assertNotNull(line);
+        assertEquals(2, line.getRevision());
+        assertEquals("rayjandom", line.getAuthor());
+        assertArrayEquals(lineOut, line.getLine());
+    }
+
+    /**
      * Test commit of arbitrary revprops.
      * @throws Throwable
      * @since 1.5
@@ -4679,6 +4723,7 @@ public class BasicTests extends SVNTests
         return callback.getMessages();
     }
 
+    @SuppressWarnings("deprecation")
     private byte[] collectBlameLines(String path, Revision pegRevision,
                                      Revision revisionStart,
                                      Revision revisionEnd,
@@ -4766,6 +4811,7 @@ public class BasicTests extends SVNTests
     }
 
     /* A blame callback implementation. */
+    @SuppressWarnings("deprecation")
     protected class BlameCallbackImpl implements BlameCallback
     {
 
@@ -4978,6 +5024,146 @@ public class BasicTests extends SVNTests
             }
         }
     }
+
+    /* A blame callback implementation. */
+    protected class BlameLineCallbackImpl implements BlameLineCallback
+    {
+
+        /** list of blame records (lines) */
+        private List<BlameLine> lines = new ArrayList<BlameLine>();
+
+        public void singleLine(long lineNum, long rev,
+                               Map<String, byte[]> revProps,
+                               long mergedRevision,
+                               Map<String, byte[]> mergedRevProps,
+                               String mergedPath, boolean localChange,
+                               byte[] line)
+            throws ClientException
+        {
+            DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
+
+            try {
+                insertLine(
+                    df.parse(new String(revProps.get("svn:date"))),
+                    rev,
+                    new String(revProps.get("svn:author")),
+                    mergedRevProps == null ? null
+                        : df.parse(new String(mergedRevProps.get("svn:date"))),
+                    mergedRevision,
+                    mergedRevProps == null ? null
+                        : new String(mergedRevProps.get("svn:author")),
+                    mergedPath, line);
+            } catch (ParseException e) {
+                throw ClientException.fromException(e);
+            }
+        }
+
+        private Date getDate(Date date, Date merged_date) {
+            return (merged_date == null ? date : merged_date);
+        }
+
+        private String getAuthor(String author, String merged_author) {
+            return (merged_author == null ? author : merged_author);
+        }
+
+        private long getRevision(long revision, long merged_revision) {
+            return (merged_revision == -1 ? revision : merged_revision);
+        }
+
+        private void insertLine(Date date, long revision, String author,
+                                Date merged_date, long merged_revision,
+                                String merged_author, String merged_path,
+                                byte[] line)
+        {
+            this.lines.add(new BlameLine(getRevision(revision, merged_revision),
+                                         getAuthor(author, merged_author),
+                                         getDate(date, merged_date),
+                                         line));
+        }
+
+        /**
+         * Retrieve the number of line of blame information
+         * @return number of lines of blame information
+         */
+        public int numberOfLines()
+        {
+            return this.lines.size();
+        }
+
+        /**
+         * Retrieve blame information for specified line number
+         * @param i the line number to retrieve blame information about
+         * @return  Returns object with blame information for line
+         */
+        public BlameLine getBlameLine(int i)
+        {
+            if (i >= this.lines.size())
+            {
+                return null;
+            }
+            return this.lines.get(i);
+        }
+
+        /**
+         * Class represeting one line of the lines, i.e. a blame record
+         */
+        public final class BlameLine
+        {
+            private long revision;
+            private String author;
+            private Date changed;
+            private byte[] line;
+
+            /**
+             * Constructor
+             *
+             * @param revision
+             * @param author
+             * @param changed
+             * @param line
+             */
+            public BlameLine(long revision, String author,
+                             Date changed, byte[] line)
+            {
+                this.revision = revision;
+                this.author = author;
+                this.changed = changed;
+                this.line = line;
+            }
+
+            /**
+             * @return Returns the author.
+             */
+            public String getAuthor()
+            {
+                return author;
+            }
+
+            /**
+             * @return Returns the date changed.
+             */
+            public Date getChanged()
+            {
+                return changed;
+            }
+
+            /**
+             * @return Returns the source line content.
+             */
+            public byte[] getLine()
+            {
+                return line;
+            }
+
+            /**
+             * @return Returns the revision.
+             */
+            public long getRevision()
+            {
+                return revision;
+            }
+        }
+    }
 
     /** A helper which calls update with a bunch of default args. */
     private long update(OneTest thisTest)

Modified: subversion/trunk/subversion/bindings/javahl/tests/org/apache/subversion/javahl/ExceptionTests.java
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/bindings/javahl/tests/org/apache/subversion/javahl/ExceptionTests.java?rev=1851333&r1=1851332&r2=1851333&view=diff
==============================================================================
--- subversion/trunk/subversion/bindings/javahl/tests/org/apache/subversion/javahl/ExceptionTests.java (original)
+++ subversion/trunk/subversion/bindings/javahl/tests/org/apache/subversion/javahl/ExceptionTests.java Tue Jan 15 10:20:26 2019
@@ -206,18 +206,17 @@ public class ExceptionTests extends SVNT
         {
             client.blame(thisTest.getWorkingCopy() + "/iota",
                          Revision.getInstance(1), Revision.getInstance(1),
-                         Revision.getInstance(1), false, false,
-                         new BlameCallback()
-                          {
-                            public void singleLine(long lineNum, long revision,
-                                                   Map<String, byte[]> revProps, long mergedRevision,
-                                                   Map<String, byte[]> mergedRevProps,
-                                                   String mergedPath, String line,
-                                                   boolean localChange)
-                            {
-                                throw new TestException("inner", theException);
-                            }
-                          });
+                         Revision.getInstance(1), false, false, null,
+                         new BlameLineCallback() {
+                             public void singleLine(long lineNum, long revision,
+                                                    Map<String, byte[]> revProps, long mergedRevision,
+                                                    Map<String, byte[]> mergedRevProps,
+                                                    String mergedPath, boolean localChange,
+                                                    byte[] line)
+                             {
+                                 throw new TestException("inner", theException);
+                             }
+                         });
         }
         catch (ClientException e)
         {