This library seems to do the trick: google-diff-match-patch. It can create a patch string from differences and allow to reapply the patch.
edit: Another solution might be to https://code.google.com/p/java-diff-utils/
Answer from bernardn on Stack OverflowThis library seems to do the trick: google-diff-match-patch. It can create a patch string from differences and allow to reapply the patch.
edit: Another solution might be to https://code.google.com/p/java-diff-utils/
Apache Commons has String diff
org.apache.commons.lang.StringUtils
StringUtils.difference("foobar", "foo");
Might be a little late, but I was in the same situation like you and ended up creating my own library for exactly your use-case. Since I was forced to come up with a solution myself, I decided to release it on Github, to spare others the hard work. You can find it here: https://github.com/SQiShER/java-object-diff
--- Edit ---
Here is a little usage example based on the OPs code:
SomeClass a = new SomeClass();
SomeClass b = new SomeClass();
a.setProp1("A");
a.setProp2("X");
b.setProp1("B");
b.setProp2("X");
DiffNode diff = ObjectDifferBuilder.buildDefault().compare(a, b);
assert diff.hasChanges();
assert diff.childCount() == 1;
assert diff.getChild('prop1').getState() == DiffNode.State.CHANGED;
http://javers.org is library that does exacly what you need: has methods like compare(Object leftGraph, Object rightGraph) returning the Diff object. Diff contains a list of changes (ReferenceChange, ValueChange, PropertyChange) e.g.
given:
DummyUser user = dummyUser("id").withSex(FEMALE).build();
DummyUser user2 = dummyUser("id").withSex(MALE).build();
Javers javers = JaversTestBuilder.newInstance()
when:
Diff diff = javers.compare(user, user2)
then:
diff.changes.size() == 1
ValueChange change = diff.changes[0]
change.leftValue == FEMALE
change.rightValue == MALE
It can handle cycles in graphs.
In addition you can get Snapshot of any graph object. Javers has JSON serializers and deserializers to snapshot, and changes so you can easily save them in database. With this library you can easily implement a module for auditing.
private static final String NL = "\n";
I don't think that NL is a particularly good name. Generally it is not needed either. For a system utility, I'd go for System.lineSeparator().
public static void main(String[] args) {
There is a lot of duplicate code in the main method because reading the files is parallelized. Reading the files can be separated out into a a single method so that the duplicate code is not required (in this case just calling readLines would do the same thing I suppose).
if (args.length != 2) {
return;
}
I'd at least return a message to the user what kind of arguments are required, and then use System.exit() with a return/status code. You do this later on, strangely enough, so symmetry is also missing.
BufferedReader oldSourceBufferedReader = null;
BufferedReader newSourceBufferedReader = null;
try {
oldSourceBufferedReader =
new BufferedReader(new FileReader(oldSourceFile));
I'd expect try-with-resources to be used here, it would remove a lot of unnecessary code, and would avoid any null handling.
return printDiff(matrix, oldSourceLines, newSourceLines);
printDiff is a bad name, as the method doesn't actually print anything.
int[][] matrix = new int[oldSourceLines.size() + 1]
[newSourceLines.size() + 1];
Here you can see clearly what happens, but it is unclear from the code why the matrix has the calculated size. Whenever that happens you need code comments.
Furthermore, it seems your matrix is over-dimensioned in both directions by one, as you only index i - 1 and j - 1.
for (int i = 1; i <= oldSourceLines.size(); ++i) {
Nah, you should always try and use zero based indexing. Whenever you need one more, you can add it when needed. Subtraction always confuses things.
The same goes for ++i. Sometimes people things that ++i is faster, but it is no different than i++ and less clear.
private static void printDiff(StringBuilder stringBuilder,
int[][] matrix,
List<String> oldSourceLines,
List<String> newSourceLines,
int i,
int j) {
This is a recursive method, and recursive methods should always be documented. Furthermore, for recursive methods, it is pretty important to make it very clear when the end is reached. I would recommend to check for a negative i and j to quickly return. Also, to make the method more readable, you could simply change i and / or j and then perform the recursion at the end.
Design. Yes, you always need a specific class that you instantiate, so that you can use it from other code without having to use main.
Currently the used algorithm is not described. This is vital for maintainability. Always document the algorithm and / or provide a reference to the method used.
When creating a diff I would strongly suggest to make sure that you don't need to read entire files in memory. Files can be huge after all. Otherwise you may want to limit the file size
Rather than your readLine() loops prefer Files.readAllLines(). This has the side-effect of fixing a problem where your BufferedReader instances are not protected within a try-with-resources block (since no readers will be necessary).
Consider writing an error message if the number of CLI arguments is incorrect. You should probably also System.exit(1); rather than only return, as the latter will make it look like the program succeeded.
printDiff could be better-named as formatDiff since it doesn't actually print.
Otherwise seems fine (though I have not critically examined the inner diff algorithm).
This library seems to be what you're after: google-diff-match-patch.
It has the following main features:
- Diff: Compare two blocks of plain text and efficiently return a list of differences.
- Match: Given a search string, find its best fuzzy match in a block of plain text. Weighted for both accuracy and location.
- Patch: Apply a list of patches onto plain text. Use best-effort to apply patch even when the underlying text doesn't match.
In case you want an alternative, you could also try this: java-diff-utils
Hi You can run a MR job which can use https://code.google.com/p/google-diff-match-patch/ to do the required job. I dont feel there are any tools out of the box to do your job.