Copy all kind of RELATIONS from one workbook to new workbook Apache POI XSSFWorkbook
<p>I have been trying to take relations from one workbook and copying them over to another newly created workbook. 
So far I have tried this:</p>

<pre><code>XSSFWorkbook oldWB = new XSSFWorkbook(new File("F:\\pivottablesurvey.xlsx")); //src workbook
XSSFWorkbook newWB = new XSSFWorkbook(); //target workbook

POIXMLDocument upcastOldwb = oldWB; //Upcasting
POIXMLDocument upcastNewwb = newWB; //Upcasting

for (PackageRelationship pr : upcastOldwb.getPackagePart().getRelationships()) {
   upcastNewwb.getPackagePart().getRelatedPart(pr).addRelationship(pr.getTargetURI(),pr.getTargetMode(), pr.getRelationshipType());       
}
</code></pre>

<p>At this point, I get this error:</p>

<pre><code>Exception in thread "main" java.lang.IllegalArgumentException: Relationship id=rId1 - container=org.apache.poi.openxml4j.opc.ZipPackage@5ffdc730 - relationshipType=http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet - source=/xl/workbook.xml - target=/xl/worksheets/sheet1.xml,targetMode=INTERNAL doesn't start with this part /xl/workbook.xml
</code></pre>

<p>First of all, I will admit that I don't even know if the approach that I have taken is correct. I am just trying to copy relations from one workbook to another workbook. 
Any help will be appreciated.</p>

<p>Thanks</p>

<p><strong>Edit 2</strong></p>

<p>Is this what you are referring to when you say that that part has to exist first?</p>

<pre><code>XSSFWorkbook oldWB = new XSSFWorkbook(new File("F:\\pivottablesurvey.xlsx")); //src workbook
XSSFWorkbook newWB = new XSSFWorkbook(); //target workbook

POIXMLDocument upcastOldwb = oldWB; //Upcasting
POIXMLDocument upcastNewwb = newWB; //Upcasting
//Different code from above (the actual question). Is this what you thought I missed?
for (PackageRelationship pr : upcastOldwb.getPackagePart().getRelationships()) {
         URI target = pr.getTargetURI();
           if(target.getFragment() != null) {
              String t = target.toString();
              try {
                 target = new URI( t.substring(0, t.indexOf('#')) );
              } catch(URISyntaxException e) {
                 throw new InvalidFormatException("Invalid target URI: " + target);
              }
           }               
           PackagePartName relName = PackagingURIHelper.createPartName(target);
           upcastNewwb.getPackagePart().getPackage().createPart(relName, upcastOldwb.getPackagePart().getContentType());               
    }
</code></pre>

<p><strong>Edit 1:</strong></p>

<p>My ultimate goal is to copy sheet(s) from one workbook to another. There are other suggestions/solutions. I even implemented one by myself without looking at other solutions. </p>

<p>I implemented the suggestion <a href="https://stackoverflow.com/a/5891026/4828463">given here by Gagravarr.</a> As it turned out, my implementation is 99 % the same as other solutions found here on SO and coderanch. But there is a problem with that solution. If the sheets contains tables, pictures, graphs, etc, then those solutions don't work well.</p>

<p>Then I thought of a clever way to copy sheets to new workbook: <a href="https://stackoverflow.com/q/41219942/4828463">By process of Elimination!</a> This solution is the best out of the rest. It keeps everything intact and no graph, chart, picture would break. But as you can tell, that is a hacky way. Not the cool way. So I want to implement something that is a proper way. Or a professional developer way. </p>

<p>So to do this, I looked into <code>XSSFWorkbook.cloneSheet(...)</code> method and how it is implemented by developers at Apache. I am trying to replicate it. So far in my attempt, every thing is going according to the plan, with one little problem. And that problem is the original question above. Let me show you my code first:</p>

<pre><code>public static void main(String[] args) throws Exception {
XSSFWorkbook oldWB = new XSSFWorkbook(new File("F:\\faraz\\Documents\\pivottablesurvey.xlsx"));
XSSFWorkbook newWB = new XSSFWorkbook();

for (int i = 0; i &lt; oldWB.getNumberOfSheets(); i++) {
    XSSFSheet sheetFromOldWB = (XSSFSheet) oldWB.getSheetAt(i);
    XSSFSheet sheetForNewWB = (XSSFSheet) newWB.createSheet(sheetFromOldWB.getSheetName());
    /*
     * Behold! Below this point, I am trying to mimic XSSFWorkbook.cloneSheet(...) method
     */
    List&lt;RelationPart&gt; rels = sheetFromOldWB.getRelationParts();            
     XSSFDrawing dg = null;
        for(RelationPart rp : rels) {
            POIXMLDocumentPart r = rp.getDocumentPart();
            if(r instanceof XSSFDrawing) {                  
                dg = (XSSFDrawing)r;
                continue;
            }                   
            addRelation(rp, sheetForNewWB); //This is a private method in XSSFWorkbook class so I copied this method over to this class
        }               
        try {
            for(PackageRelationship pr : sheetFromOldWB.getPackagePart().getRelationships()) {
                if (pr.getTargetMode() == TargetMode.EXTERNAL) {
                    sheetForNewWB.getPackagePart().addExternalRelationship
                        (pr.getTargetURI().toASCIIString(), pr.getRelationshipType(), pr.getId());
                }
            }
        } catch (InvalidFormatException e) {
            throw new POIXMLException("Failed to clone sheet", e);
        }                   
        OutputStream out = new ByteArrayOutputStream();
        Method writeReflect = sheetFromOldWB.getClass().
                getDeclaredMethod("write", OutputStream.class); //I had to use reflection here to get it to work because write(OutputStream os) is a private method in XSSFWorkbook class               
        writeReflect.setAccessible(true);
        Object w = writeReflect.invoke(sheetFromOldWB,out);             
        Method readReflect = sheetFromOldWB.getClass().
                getDeclaredMethod("read", InputStream.class);   //Same reason as above              
        readReflect.setAccessible(true);
        Object r = readReflect.invoke(sheetForNewWB,new ByteArrayInputStream(((ByteArrayOutputStream) out).toByteArray()));             
        CTWorksheet ct = sheetForNewWB.getCTWorksheet();
            if(ct.isSetLegacyDrawing()) {
                System.out.println("Cloning sheets with comments is not yet supported.");
                ct.unsetLegacyDrawing();
            }
            if (ct.isSetPageSetup()) {
                System.out.println("Cloning sheets with page setup is not yet supported.");
                ct.unsetPageSetup();
            }
            sheetForNewWB.setSelected(false); 
            if (dg != null) {
                if(ct.isSetDrawing()) {                       
                    ct.unsetDrawing();
                }
                XSSFDrawing clonedDg = sheetForNewWB.createDrawingPatriarch();                     
                clonedDg.getCTDrawing().set(dg.getCTDrawing());
                clonedDg = sheetForNewWB.createDrawingPatriarch();                 
                List&lt;RelationPart&gt; srcRels = sheetFromOldWB.createDrawingPatriarch().getRelationParts();
                for (RelationPart rp : srcRels) {
                    addRelation(rp, clonedDg);
                }
            }
}
FileOutputStream fileOut = new FileOutputStream("F:\\faraz\\Documents\\output.xlsx");
newWB.write(fileOut);
oldWB.close();
newWB.close();
fileOut.close();
}

private static void addRelation(RelationPart rp, POIXMLDocumentPart target) {
PackageRelationship rel = rp.getRelationship();
if (rel.getTargetMode() == TargetMode.EXTERNAL) {
    target.getPackagePart().addRelationship(
        rel.getTargetURI(), rel.getTargetMode(), rel.getRelationshipType(), rel.getId());
} else {        
    XSSFRelation xssfRel = XSSFRelation.getInstance(rel.getRelationshipType());

    if (xssfRel == null) {
        throw new POIXMLException("Can't clone sheet - unknown relation type found: "+rel.getRelationshipType());
    } 
    **target.addRelation(rel.getId(), xssfRel, rp.getDocumentPart());**
}
}
</code></pre>

<p>That line with double astericks <code>target.addRelation(rel.getId(), xssfRel, rp.getDocumentPart());</code> is giving me a trouble. When I run this program as is, I get this error:</p>

<pre><code>Exception in thread "main" java.lang.IllegalArgumentException: No part found for relationship id=rId1 - container=org.apache.poi.openxml4j.opc.ZipPackage@50c91c07 - relationshipType=http://schemas.openxmlformats.org/officeDocument/2006/relationships/pivotTable - source=/xl/worksheets/sheet1.xml - target=/xl/pivotTables/pivotTable1.xml,targetMode=INTERNAL
at org.apache.poi.openxml4j.opc.PackagePart.getRelatedPart(PackagePart.java:487)
at org.apache.poi.POIXMLDocumentPart.findExistingRelation(POIXMLDocumentPart.java:378)
at org.apache.poi.POIXMLDocumentPart.addRelation(POIXMLDocumentPart.java:343)
at oldmain.addRelation(oldmain.java:112)
at oldmain.main(oldmain.java:50)
</code></pre>

<p>It is looking for relations at this point! Actually, I should say I believe its looking for relation inside the workbook because I am not sure. But it cannot find them there because I am not cloning the sheets within the same workbook. </p>

<p>And this is my actual question here. What is it looking for here? Is what I think is correct? Is it actually looking for some relations inside the workbook? If my thinking is correct, then I need to copy all relations from source workbook to new workbook. </p>

<p>One thing, if I just comment out that line, then the method works okay. It would copy over everything but the graphs or pictures don't look good. I mean, it would copy over the Integers and Strings, etc but the graphs, pictures and charts would be missing. Let me show you what I meant:</p>

<p><strong>Source Sheet:</strong>
<a href="https://i.stack.imgur.com/UV1Cf.jpg" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/UV1Cf.jpg" alt="Source Sheet"></a></p>

<p><strong>Result Sheet:</strong>
<a href="https://i.stack.imgur.com/4SliF.jpg" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/4SliF.jpg" alt="Result Sheet"></a></p>

<p><strong>Source Sheet:</strong>
<a href="https://i.stack.imgur.com/iC6zF.jpg" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/iC6zF.jpg" alt="Source Sheet"></a></p>

<p><strong>Result Sheet:</strong>
<a href="https://i.stack.imgur.com/MuvvR.jpg" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/MuvvR.jpg" alt="Result Sheet"></a></p>

<p>You see that, it is working somewhat but not fully. And I believe that's because it's missing some kind of relations. Now, why I came to that realization is because I dug inside that line to see what is it calling and what does it want.</p>

<p>So, is it possible to copy all the relations from one workbook to another? Is it actually what I need for this code to work?</p>

<p>Thanks again and I shall really appreciate any help. </p>