package org.codehaus.mojo.jardiff; import org.apache.maven.doxia.sink.Sink; import org.osjava.jardiff.ClassInfo; import org.osjava.jardiff.DiffException; import org.osjava.jardiff.DiffHandler; import org.osjava.jardiff.FieldInfo; import org.osjava.jardiff.MethodInfo; import org.objectweb.asm.Type; public final class SinkDiffHandler implements DiffHandler { private final Sink sink; private int changeLevel; private String currentClass; public SinkDiffHandler( final Sink sink ) { this.sink = sink; this.changeLevel = 0; } public void startDiff(String from, String to) throws DiffException { sink.section1(); sink.sectionTitle1(); sink.text("API differences between " + from + " and " + to); sink.sectionTitle1_(); } public void contains(ClassInfo contains) throws DiffException { } public void startNewContents() throws DiffException { } public void endNewContents() throws DiffException { } public void startOldContents() throws DiffException { } public void endOldContents() throws DiffException { } // removed classes public void startRemoved() throws DiffException { if (changeLevel == 0) { sink.section2(); sink.sectionTitle2(); sink.text("Classes removed"); sink.sectionTitle2_(); sink.list(); } else if (changeLevel == 1) { sink.bold(); sink.text("Removed:"); sink.bold_(); sink.lineBreak(); sink.list(); } // class changed remove } public void classRemoved(ClassInfo removed) throws DiffException { sink.listItem(); sink.text(toClassName(removed.getName())); sink.listItem_(); } private String toClassName(String name) { return name.replace('/', '.'); } public void endRemoved() throws DiffException { if (changeLevel == 0) { sink.list_(); sink.section2_(); } else if(changeLevel == 1){ sink.list_(); } } // added classes public void startAdded() throws DiffException { if (changeLevel == 0) { sink.section2(); sink.sectionTitle2(); sink.text("Classes added"); sink.sectionTitle2_(); sink.list(); } else if (changeLevel == 1) { sink.bold(); sink.text("Added:"); sink.bold_(); sink.lineBreak(); sink.list(); } } public void classAdded(ClassInfo added) throws DiffException { sink.listItem(); sink.text(toClassName(added.getName())); sink.listItem_(); } public void endAdded() throws DiffException { if (changeLevel == 0) { sink.list_(); sink.section2_(); } else if (changeLevel == 1) { sink.list_(); } } // changed classes public void startChanged() throws DiffException { if (changeLevel == 0) { sink.section2(); sink.sectionTitle2(); sink.text("Classes changed"); sink.sectionTitle2_(); } if (changeLevel == 1) { sink.bold(); sink.text("Changed:"); sink.bold_(); sink.lineBreak(); sink.list(); } changeLevel++; } public void startClassChanged(String changed) throws DiffException { sink.section3(); sink.sectionTitle3(); sink.text(currentClass = toClassName(changed)); sink.sectionTitle3_(); } public void classChanged(ClassInfo from, ClassInfo to) throws DiffException { sink.listItem(); sink.text("Class changed "); writeClassInfo(from); sink.bold(); sink.text(" -> "); sink.bold_(); writeClassInfo(to); sink.listItem_(); } public void methodRemoved(MethodInfo removed) throws DiffException { sink.listItem(); sink.text("Method removed: "); writeMethodInfo(removed); sink.listItem_(); } public void methodChanged(MethodInfo from, MethodInfo to) throws DiffException { sink.listItem(); sink.text("Method changed: "); writeMethodInfo(from); sink.bold(); sink.text(" -> "); sink.bold_(); writeMethodInfo(to); sink.listItem_(); } public void methodAdded(MethodInfo added) throws DiffException { sink.listItem(); sink.text("Method added: "); writeMethodInfo(added); sink.listItem_(); } public void fieldRemoved(FieldInfo removed) throws DiffException { sink.listItem(); sink.text("Field removed: "); writeFieldInfo(removed); sink.listItem_(); } public void fieldChanged(FieldInfo from, FieldInfo to) throws DiffException { sink.listItem(); sink.text("Field changed: "); writeFieldInfo(from); sink.bold(); sink.text(" -> "); sink.bold_(); writeFieldInfo(to); sink.listItem_(); } public void fieldAdded(FieldInfo added) throws DiffException { sink.listItem(); sink.text("Field added: "); writeFieldInfo(added); sink.listItem_(); } public void endClassChanged() throws DiffException { sink.section3_(); } public void endChanged() throws DiffException { changeLevel--; if (changeLevel == 0) { sink.section2_(); } } // end public void endDiff() throws DiffException { sink.section1_(); } private void writeMethodInfo(MethodInfo info) { if(info.isDeprecated()) { sink.italic(); sink.text("deprecated "); sink.italic_(); } sink.text(info.getAccessType() +" "); if(info.isFinal()) { sink.text("final "); } if(info.isStatic()) { sink.text("static "); } if(info.isSynchronized()) { sink.text("synchronized "); } if(info.isAbstract()) { sink.text("abstract "); } if(info.getDesc() != null && !info.getName().equals("<init>")) { Type returnType = Type.getReturnType(info.getDesc()); writeType(returnType); sink.text(" "); } if(info.getName().equals("<init>")) { sink.text(currentClass); } else { sink.text(info.getName()); } if(info.getDesc() != null) { Type[] types = Type.getArgumentTypes(info.getDesc()); sink.text("("); for(int t = 0; t < types.length; t++) { Type origType = types[t]; writeType(origType); if(t < types.length-1) { sink.text(", "); } } sink.text(") "); } if(info.getExceptions() != null && info.getExceptions().length > 0) { sink.text("throws "); for(int i = 0; i < info.getExceptions().length; i++) { sink.text(toClassName(info.getExceptions()[i])); if(i < info.getExceptions().length-1) { sink.text(", "); } } } } private void writeType(Type origType) { Type type = origType; int i = origType.getSort(); if (i == Type.ARRAY) { type = origType.getElementType(); i = type.getSort(); } switch (i) { case Type.BOOLEAN: sink.text("boolean"); break; case Type.BYTE: sink.text("byte"); break; case Type.CHAR: sink.text("char"); break; case Type.DOUBLE: sink.text("double"); break; case Type.FLOAT: sink.text("float"); break; case Type.INT: sink.text("int"); break; case Type.LONG: sink.text("long"); break; case Type.OBJECT: sink.text(origType.getClassName()); break; case Type.SHORT: sink.text("short"); break; case Type.VOID: sink.text("void"); break; } if (origType.getSort() == Type.ARRAY) { for(int d = 0; d < origType.getDimensions(); d++) { sink.text("[]"); } } } private void writeClassInfo(ClassInfo info) { if(info.isDeprecated()) { sink.italic(); sink.text("deprecated "); sink.italic_(); } sink.text(info.getAccessType() +" "); if(info.isAbstract()) { sink.text("abstract "); } if(info.isStatic()) { sink.text("static "); } if(info.isFinal()) { sink.text("final "); } if(info.getName().equals("<init>")) { sink.text("<init> "); } sink.text(toClassName(info.getName()) +" "); if(info.getSupername() != null) { sink.text("extends " + toClassName(info.getSupername()) +" "); } if(info.getInterfaces() != null && info.getInterfaces().length > 0) { sink.text("implements "); for(int i = 0; i < info.getInterfaces().length; i++) { sink.text(toClassName(info.getInterfaces()[i])); if(i < info.getInterfaces().length-1) { sink.text(", "); } } } } private void writeFieldInfo(FieldInfo info) { if(info.isDeprecated()) { sink.italic(); sink.text("deprecated "); sink.italic_(); } sink.text(info.getAccessType() +" "); if(info.isFinal()) { sink.text("final "); } if(info.isStatic()) { sink.text("static "); } if(info.isTransient()) { sink.text("transient "); } if(info.isVolatile()) { sink.text("volatile "); } if(info.getName().equals("<init>")) { sink.text("<init> "); } if(info.getDesc() != null) { Type type = Type.getType(info.getDesc()); writeType(type); } sink.text(" " +info.getName() +" "); if(info.getValue() != null) { sink.text("=" +(info.getValue() instanceof String ? "\"" + info.getValue() +"\"" : info.getValue().toString())); } } }