public Object clone() {
    MergeJoinMeta retval = (MergeJoinMeta) super.clone();
    int nrKeys1 = keyFields1.length;
    int nrKeys2 = keyFields2.length;
    retval.allocate( nrKeys1, nrKeys2 );
    System.arraycopy( keyFields1, 0, retval.keyFields1, 0, nrKeys1 );
    System.arraycopy( keyFields2, 0, retval.keyFields2, 0, nrKeys2 );

    StepIOMetaInterface stepIOMeta = new StepIOMeta( true, true, false, false, false, false );
    List<StreamInterface> infoStreams = getStepIOMeta().getInfoStreams();

    for ( StreamInterface infoStream : infoStreams ) {
      stepIOMeta.addStream( new Stream( infoStream ) );
    }
    retval.setStepIOMeta( stepIOMeta );

    return retval;
  }
@Test
  public void cloneTest() throws Exception {
    MergeJoinMeta meta = new MergeJoinMeta();
    meta.allocate( 2, 3 );
    meta.setKeyFields1( new String[] { "kf1-1", "kf1-2" } );
    meta.setKeyFields2( new String[] { "kf2-1", "kf2-2", "kf2-3" } );
    // scalars should be cloned using super.clone() - makes sure they're calling super.clone()
    meta.setJoinType( "INNER" );
    MergeJoinMeta aClone = (MergeJoinMeta) meta.clone();
    assertFalse( aClone == meta ); // Not same object returned by clone
    assertTrue( Arrays.equals( meta.getKeyFields1(), aClone.getKeyFields1() ) );
    assertTrue( Arrays.equals( meta.getKeyFields2(), aClone.getKeyFields2() ) );
    assertEquals( meta.getJoinType(), aClone.getJoinType() );

    assertNotNull( aClone.getStepIOMeta() );
    assertFalse( meta.getStepIOMeta() == aClone.getStepIOMeta() );
    List<StreamInterface> infoStreams = meta.getStepIOMeta().getInfoStreams();
    List<StreamInterface> cloneInfoStreams = aClone.getStepIOMeta().getInfoStreams();
    assertFalse( infoStreams == cloneInfoStreams );
    int streamSize = infoStreams.size();
    assertTrue( streamSize == cloneInfoStreams.size() );
    for ( int i = 0; i < streamSize; i++ ) {
      assertFalse( infoStreams.get( i ) == cloneInfoStreams.get( i ) );
    }
  }