To fix the problem we need to create a version of IntegerIterator that has public Integer next() (to satisfy Iterator<Integer> ), but also has public int next() from version 1.

// version 2.1 public final class IntegerIterator implements Iterator < Integer >{ private final int [] ints ; private int i ; public IntegerIterator ( int [] ints ) { this .ints = ints; this .i = 0; } public int next () { return next().intValue(); // call to "public Integer next()" } @Override public Integer next () { if (!hasNext()) { throw new NoSuchElementException (); } return ints[i++]; } @Override public boolean hasNext () { return i < ints. length ; } @Override public void remove () { throw new UnsupportedOperationException (); } }

Trying to compile version 2.1 give us several errors. The main one is that java does not allow two methods with the same name and arguments in the same class, even when their return types are different.

v2.1/IntegerIterator.java:19: error: method next() is already defined in class IntegerIterator public Integer next() { ^ v2.1/IntegerIterator.java:5: error: IntegerIterator is not abstract and does not override abstract method next() in Iterator public final class IntegerIterator implements Iterator<Integer>{ ^ v2.1/IntegerIterator.java:14: error: next() in IntegerIterator cannot implement next() in Iterator public int next() { ^ return type int is not compatible with Integer where E is a type-variable: E extends Object declared in interface Iterator v2.1/IntegerIterator.java:15: error: int cannot be dereferenced return next().intValue(); ^ 4 errors

However, in java bytecode it is allowed to have two methods with the same name and arguments but different return values.

Rather than rely on a java compiler to create our version 2.1 IntegerIterator.class , we can build it ourselves with the BCEL library:

import org . apache . bcel .*; import org . apache . bcel . classfile .*; import org . apache . bcel . generic .*; public final class IntegerIteratorCreator { public static final void main ( String [] args ) throws Exception { JavaClass master = Repository.lookupClass( "IntegerIterator" ); // version 2 ClassGen cg = new ClassGen (master); InstructionList il = new InstructionList (); // public int next() MethodGen mg = new MethodGen ( Constants .ACC_PUBLIC, Type .INT, Type .NO_ARGS, new String [0], "next" , "IntegerIterator" , il, cg.getConstantPool()); InstructionFactory factory = new InstructionFactory (cg); // The bytecode instructions for "return next().intValue();" // where next() is the next method that returns an Integer. il.append( factory .ALOAD_0); il.append(factory.createInvoke( "IntegerIterator" , "next" , Type.getReturnType( "Ljava/lang/Integer;" ), Type .NO_ARGS, Constants .INVOKEVIRTUAL)); il.append(factory.createInvoke( "java.lang.Integer" , "intValue" , Type .INT, Type .NO_ARGS, Constants .INVOKEVIRTUAL)); il.append(factory.createReturn( Type .INT)); mg.setMaxStack(); cg.addMethod(mg.getMethod()); // write out IntegerIterator.class String output = master.getClassName() + ".class" ; cg.getJavaClass().dump(output); } }

We now have a version 2.1 IntegerIterator.class file with our two next() methods. Note that we also have public java.lang.Object next(); , this method is added by the regular java compiler.

danamlund$ javap IntegerIterator.class Compiled from "IntegerIterator.java" public final class IntegerIterator implements java.util.Iterator<java.lang.Integer> { public IntegerIterator(int[]); public java.lang.Integer next(); public boolean hasNext(); public void remove(); public java.lang.Object next(); public int next(); }

Let us again review what happens when we compile and use the program Usage1 with version 1, version 2, and version 2.1 of IntegerIterator .

Case Compile Run Outcome Reason Working version 1 version 1 Works Binary compatible version 1 version 2 Runtime error Cannot find int next() Binary compatible 2 version 1 version 2.1 Works Finds the int next() we added to bytecode Forward compatible version 2 version 1 Runtime error Cannot find Integer next() Source compatible version 2 version 2 Works The compiler does not care about return type when calling methods, it calls the version 2 method Integer next() Binary compatible 3 version 2 version 2.1 Works Finds Integer next() Forward compatible 2 version 2.1 version 1 Runtime error Cannot find Integer next() Source compatible 2 version 2.1 version 2 Works The compiler chooses Integer next() and ignores int next() without complaint Source compatible 3 version 2.1 version 2.1 Works The compiler chooses Integer next() and ignores int next() without complaint

Case Binary compatible 2 and 3 shows that our change is now binary compatible. We also see that our change is source compatible from Case Source compatible 3.

A downside to handcrafting class files is that developing and publishing the library becomes more difficult. It is a good idea to create script that generates IntegerIterator.class and bundles it by itself in a jar file. The library source can then depend on IntegerIterator.jar without having a version of IntegerIterator.java lying around.