All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.javers.core.Changes Maven / Gradle / Ivy

There is a newer version: 7.6.2
Show newest version
package org.javers.core;

import org.javers.common.collections.Lists;
import org.javers.common.string.PrettyValuePrinter;
import org.javers.common.validation.Validate;
import org.javers.core.commit.CommitMetadata;
import org.javers.core.diff.Change;
import org.javers.core.diff.changetype.PropertyChange;
import org.javers.core.metamodel.object.GlobalId;
import org.javers.repository.jql.JqlQuery;

import java.io.Serializable;
import java.util.*;
import java.util.stream.Collectors;

import static java.util.Collections.unmodifiableList;
import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.toList;
import static org.javers.common.validation.Validate.argumentIsNotNull;

/**
 * Convenient wrapper for the list of Changes returned by {@link Javers#findChanges(JqlQuery)}.
 * 

* Can be used as List<Change>, * but also provides additional methods: *

* *
    *
  • {@link #groupByCommit()}, {@link #groupByObject()} — * allow traversing over the list of Changes grouped by commits * and grouped by objects
  • *
  • {@link #getChangesByType(Class)} — a subset of Changes with a given type *
  • {@link #prettyPrint()} — prints Changes to a String, nicely formatted, user-readable style *
  • {@link #devPrint()} — prints Changes to a String, simple and technical style *
* * @see http://javers.org/documentation/repository-examples/#change-log * @since 3.9 */ public class Changes extends AbstractList implements Serializable { private final List changes; private final transient PrettyValuePrinter valuePrinter; public Changes(List changes, PrettyValuePrinter valuePrinter) { Validate.argumentsAreNotNull(changes, valuePrinter); this.changes = Collections.unmodifiableList(changes); this.valuePrinter = valuePrinter; } /** * Returns changes grouped by commits. *
* * When formatting a changelog, * usually you need to group changes by commits and then by objects. *

* * A simple changelog, like {@link #devPrint()}, can be printed by this code: *

* *
     * changes.groupByCommit().forEach(byCommit -> {
     *   System.out.println("commit " + byCommit.getCommit().getId());
     *   byCommit.groupByObject().forEach(byObject -> {
     *     System.out.println("  changes on " + byObject.getGlobalId().value() + ":");
     *     byObject.get().forEach(change -> System.out.println("  - " + change));
     *   });
     * });
     * 
* * @since 3.9 */ public List groupByCommit() { if (changes.size() == 0) { return Collections.emptyList(); } if (!changes.get(0).getCommitMetadata().isPresent()) { return Lists.immutableListOf( new ChangesByCommit(CommitMetadata.nullObject(), changes, valuePrinter) ); } Map> changesByCommit = changes.stream().collect( groupingBy(c -> c.getCommitMetadata().orElseThrow( () -> new IllegalStateException("No CommitMetadata in this Change")), () -> new LinkedHashMap<>(), toList())); List result = new ArrayList<>(); changesByCommit.forEach((k,v) -> { result.add(new ChangesByCommit(k, v, valuePrinter)); }); return unmodifiableList(result); } public List getPropertyChanges(String propertyName) { return (List)changes.stream() .filter(it -> it instanceof PropertyChange && ((PropertyChange) it).getPropertyName().equals(propertyName)) .collect(Collectors.toList()); } /** * Changes grouped by entities. *
* * See example in {@link #groupByCommit()} * * @since 3.9 */ public List groupByObject() { Map> changesByObject = changes.stream().collect( groupingBy(c -> c.getAffectedGlobalId().masterObjectId())); List result = new ArrayList<>(); changesByObject.forEach((k, v) -> { result.add(new ChangesByObject(k, v, valuePrinter)); }); return unmodifiableList(result); } @Override public Change get(int index) { return changes.get(index); } @Override public int size() { return changes.size(); } /** * Returns a subset of Changes with a given type */ public List getChangesByType(final Class type) { argumentIsNotNull(type); return (List) unmodifiableList( changes.stream().filter(input -> type.isAssignableFrom(input.getClass())).collect(Collectors.toList())); } /** * Delegates to {@link #devPrint()}.
* See {@link #prettyPrint()} */ @Override public String toString() { return devPrint(); } /** * Prints the list of Changes to a nicely formatted String.
* Can be used on GUI to show Changes to your users. *

* Example: *

* *
     * Changes:
     * Commit 2.00 done by author at 14 Mar 2021, 12:37:37 :
     * * changes on Employee/Frodo :
     *   - 'lastPromotionDate' = '14.37.2021 12:37'
     *   - 'performance' map changes :
     *      · entry ['1' : 'bb'] -> ['1' : 'aa']
     *      · entry ['2' : 'bb'] added
     *      · entry ['3' : 'aa'] removed
     *   - 'position' = 'Hero'
     *   - 'postalAddress.city' = 'Shire'
     *   - 'primaryAddress.city' changed: 'Shire' -> 'Mordor'
     *   - 'primaryAddress.street' = 'Some Street'
     *   - 'salary' changed: '10000' -> '12000'
     *   - 'skills' collection changes :
     *      · 'agile coaching' added
     *   - 'subordinates' collection changes :
     *      0. 'Employee/Sam' added
     * * new object: Employee/Sam
     *   - 'name' = 'Sam'
     *   - 'salary' = '10000'
     * Commit 1.00 done by author at 14 Mar 2021, 12:37:37 :
     * * new object: Employee/Frodo
     *   - 'name' = 'Frodo'
     *   - 'performance' map changes :
     *      · entry ['1' : 'bb'] added
     *      · entry ['3' : 'aa'] added
     *   - 'primaryAddress.city' = 'Shire'
     *   - 'salary' = '10000'
     *   - 'skills' collection changes :
     *      · 'management' added
     * 
*/ public final String prettyPrint() { StringBuilder b = new StringBuilder(); b.append("Changes:\n"); for (ChangesByCommit c : groupByCommit()){ b.append(c.prettyPrint()); } return b.toString(); } /** * Prints the Changes in a technical style.
* Useful for development and debugging.
*
* You can use the implementation of this method as a template to create your own changelog
* (if {@link #prettyPrint()} is not ok for you). *

* * Example: *

*
     * Changes (18):
     * commit 2.00
     *   changes on Employee/Frodo :
     *   - ValueChange{ property: 'city', left:'Shire',  right:'Mordor' }
     *   - ValueChange{ property: 'street', left:'',  right:'Some Street' }
     *   - ValueChange{ property: 'position', left:'',  right:'Hero' }
     *   - ValueChange{ property: 'salary', left:'10000',  right:'12000' }
     *   - ListChange{ property: 'subordinates', elementChanges:1 }
     *   - SetChange{ property: 'skills', elementChanges:1 }
     *   - MapChange{ property: 'performance', entryChanges:3 }
     *   - ValueChange{ property: 'lastPromotionDate', left:'',  right:'14 Mar 2021, 12:58:06+0100' }
     *   - InitialValueChange{ property: 'city', left:'',  right:'Shire' }
     *   changes on Employee/Sam :
     *   - NewObject{ new object: Employee/Sam }
     *   - InitialValueChange{ property: 'name', left:'',  right:'Sam' }
     *   - InitialValueChange{ property: 'salary', left:'',  right:'10000' }
     * commit 1.00
     *   changes on Employee/Frodo :
     *   - InitialValueChange{ property: 'city', left:'',  right:'Shire' }
     *   - NewObject{ new object: Employee/Frodo }
     *   - InitialValueChange{ property: 'name', left:'',  right:'Frodo' }
     *   - InitialValueChange{ property: 'salary', left:'',  right:'10000' }
     *   - SetChange{ property: 'skills', elementChanges:1 }
     *   - MapChange{ property: 'performance', entryChanges:2 }
     * 
     */
    public String devPrint() {
        StringBuilder b = new StringBuilder();
        b.append("Changes ("+size()+"):\n");

        groupByCommit().forEach(byCommit -> {
            b.append("commit " + byCommit.getCommit().getId() + " \n");
            byCommit.groupByObject().forEach(byObject -> {
                b.append("* changes on " + byObject.getGlobalId().value() + " :\n");
                byObject.get().forEach(change -> b.append("  - " + change + " \n"));
            });
        });

        return b.toString();
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy