Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sketch for Whitelisting audited classes & properties #615

Closed
wants to merge 38 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
d98843b
adding support to replace the toString method
ismaelgcosta Nov 30, 2017
f36f88a
adjusting style code
ismaelgcosta Nov 30, 2017
df760d3
revert invalid changes
ismaelgcosta Nov 30, 2017
681dca1
adjusting unit tests
ismaelgcosta Nov 30, 2017
803514c
sketch
bartoszwalacik Dec 3, 2017
f66014d
javadoc fix
bartoszwalacik Dec 3, 2017
e7b7de8
refactor of override toString function
ismaelgcosta Dec 4, 2017
cc98292
removing unused code
ismaelgcosta Dec 4, 2017
b6da57a
renaming test
ismaelgcosta Dec 4, 2017
4bef833
refactor for thread safe context
ismaelgcosta Dec 4, 2017
4d587a3
refactor for thread safe context
ismaelgcosta Dec 5, 2017
bd21b59
Merge branch 'master' into replace-string-id-feature
ismaelgcosta Dec 5, 2017
0d6d611
Merge branch 'master' into replace-string-id-feature
ismaelgcosta Dec 5, 2017
428c1b7
fix unit tests
ismaelgcosta Dec 5, 2017
2086a66
Merge branch 'replace-string-id-feature' of https://github.com/mundod…
ismaelgcosta Dec 5, 2017
424cafd
https://github.com/javers/javers/issues/614 removing redundant changes
bartoszwalacik Dec 8, 2017
b2d263d
https://github.com/javers/javers/issues/614 cleanup
bartoszwalacik Dec 8, 2017
0dd3c9b
https://github.com/javers/javers/issues/614 javadoc
bartoszwalacik Dec 9, 2017
1a10621
Merge pull request #617 from javers/mundodojava-replace-string-id-fea…
bartoszwalacik Dec 9, 2017
1ee2fc9
#596 fixed null values problem in CommitPropertiesConverter
Dec 18, 2017
648e907
Javers/Polyjdbc: support for db2
marvindaviddiaz Dec 18, 2017
a35a50f
#596 fixed null values problem in CommitPropertiesConverter
Dec 18, 2017
a830a7b
Merge branch 'bugfix/596/null-property-value' of https://github.com/t…
Dec 19, 2017
89ae209
Merge pull request #620 from tau3/bugfix/596/null-property-value
bartoszwalacik Dec 20, 2017
e5fc200
https://github.com/javers/javers/issues/519 added index on globalId.e…
bartoszwalacik Dec 20, 2017
0b6c518
Merge pull request #623 from javers/mongo-type-name-index
bartoszwalacik Dec 20, 2017
41f1bfb
polyjdbc updated to 0.7.2
marvindaviddiaz Dec 26, 2017
1764b15
Merge branch 'master' of https://github.com/marvindaviddiaz/javers in…
bartoszwalacik Jan 3, 2018
ce1f44a
special treatment for null constraints in DB2Dialect
bartoszwalacik Jan 4, 2018
64e7df4
special treatment for null constraints in DB2Dialect
bartoszwalacik Jan 4, 2018
dd5df48
Merge pull request #624 from javers/marvindaviddiaz-master
bartoszwalacik Jan 4, 2018
0d5aa1e
special treatment for EmbeddedId
bartoszwalacik Jan 4, 2018
caa00e9
"should map Person as EntityType"
bartoszwalacik Jan 4, 2018
d4047d3
https://github.com/javers/javers/issues/558 issue reproduction
bartoszwalacik Jan 13, 2018
fd07aa0
https://github.com/javers/javers/issues/558 issue fix
bartoszwalacik Jan 13, 2018
a59a1be
Merge pull request #627 from javers/f-aubert_2
bartoszwalacik Jan 13, 2018
1bdecfc
sketch
bartoszwalacik Dec 3, 2017
275965a
Merge branch 'included_properties' of https://github.com/javers/javer…
bartoszwalacik Jan 14, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion gradle.properties
Expand Up @@ -10,5 +10,5 @@ jodaVersion=2.9.7
mongoDbDriverVersion=3.5.0
fongoVersion=2.1.0
hibernateVersion=5.0.12.Final
polyjdbcVersion=0.7.1
polyjdbcVersion=0.7.2
aspectjweaverVersion=1.8.6
Expand Up @@ -218,30 +218,20 @@ public static List<Type> calculateHierarchyDistance(Class<?> clazz) {
return parents;
}

public static String reflectiveToString(Object cdoId) {
if (cdoId == null){
return "";
}

if (cdoId instanceof String) {
return (String) cdoId;
}

if (WellKnownValueTypes.isValueType(cdoId) || Primitives.isPrimitiveOrBox(cdoId)){
return cdoId.toString();
}
public static String reflectiveToString(Object obj) {
Validate.argumentIsNotNull(obj);

StringBuilder ret = new StringBuilder();
for (JaversField f : getAllPersistentFields(cdoId.getClass()) ){
Object val = f.getEvenIfPrivate(cdoId);
for (JaversField f : getAllPersistentFields(obj.getClass()) ){
Object val = f.getEvenIfPrivate(obj);
if (val != null) {
ret.append(val.toString());
}
ret.append(",");
}

if (ret.length() == 0) {
return cdoId.toString();
return obj.toString();
}
else{
ret.delete(ret.length()-1, ret.length());
Expand Down
5 changes: 2 additions & 3 deletions javers-core/src/main/java/org/javers/core/Javers.java
Expand Up @@ -161,8 +161,7 @@ public interface Javers {
<T> Diff compareCollections(Collection<T> oldVersion, Collection<T> currentVersion, Class<T> itemClass);

/**
* Initial diff is a kind of snapshot of given domain object graph.
* Use it alongside with {@link #compare(Object, Object)}
* Initial diff is a kind of snapshot of a given object graph.
*/
Diff initial(Object newDomainObject);

Expand Down Expand Up @@ -306,7 +305,7 @@ public interface Javers {
*DEBUG org.javers.JQL - SHALLOW query: 1 snapshots loaded (entities: 1, valueObjects: 0)
*DEBUG org.javers.JQL - DEEP_PLUS query for '...SnapshotEntity/2' at commitId 3.0, 1 snapshot(s) loaded, gaps filled so far: 1
*DEBUG org.javers.JQL - warning: object '...SnapshotEntity/3' is outside of the DEEP_PLUS+1 scope, references to this object will be nulled. Increase maxGapsToFill and fill all gaps in your object graph.
*[main] DEBUG org.javers.JQL - queryForShadows executed:
*DEBUG org.javers.JQL - queryForShadows executed:
*JqlQuery {
* IdFilter{ globalId: ...SnapshotEntity/1 }
* QueryParams{ aggregate: true, limit: 100 }
Expand Down
122 changes: 105 additions & 17 deletions javers-core/src/main/java/org/javers/core/JaversBuilder.java
Expand Up @@ -17,9 +17,9 @@
import org.javers.core.graph.GraphFactoryModule;
import org.javers.core.graph.ObjectAccessHook;
import org.javers.core.graph.TailoredJaversMemberFactoryModule;
import org.javers.core.json.JsonAdvancedTypeAdapter;
import org.javers.core.json.JsonConverter;
import org.javers.core.json.JsonConverterBuilder;
import org.javers.core.json.JsonAdvancedTypeAdapter;
import org.javers.core.json.JsonTypeAdapter;
import org.javers.core.json.typeadapter.change.ChangeTypeAdaptersModule;
import org.javers.core.json.typeadapter.commit.CommitTypeAdaptersModule;
Expand All @@ -43,7 +43,10 @@

import java.lang.reflect.Type;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;

import static org.javers.common.reflection.ReflectionUtil.*;
import static org.javers.common.validation.Validate.argumentIsNotNull;
import static org.javers.common.validation.Validate.argumentsAreNotNull;

Expand All @@ -69,7 +72,9 @@
public class JaversBuilder extends AbstractContainerBuilder {
private static final Logger logger = LoggerFactory.getLogger(JaversBuilder.class);

private final Set<ClientsClassDefinition> clientsClassDefinitions = new HashSet<>();
private final Map<Class, ClientsClassDefinition> clientsClassDefinitions = new HashMap<>();

private final Map<Class, Function<Object, String>> mappedToStringFunction = new ConcurrentHashMap<>();

private final Set<Class> classesToScan = new HashSet<>();

Expand All @@ -92,13 +97,13 @@ protected JaversBuilder() {
//conditional plugins
conditionalTypesPlugins = new HashSet<>();

if (ReflectionUtil.isClassPresent("groovy.lang.MetaClass")) {
if (isClassPresent("groovy.lang.MetaClass")) {
conditionalTypesPlugins.add(new GroovyAddOns());
}
if (ReflectionUtil.isClassPresent("org.joda.time.LocalDate")){
if (isClassPresent("org.joda.time.LocalDate")){
conditionalTypesPlugins.add(new JodaAddOns());
}
if (ReflectionUtil.isClassPresent("com.google.common.collect.Multimap")) {
if (isClassPresent("com.google.common.collect.Multimap")) {
conditionalTypesPlugins.add(new GuavaAddOns());
}

Expand Down Expand Up @@ -189,7 +194,7 @@ public JaversBuilder registerEntity(Class<?> entityClass) {
*/
public JaversBuilder registerValueObject(Class<?> valueObjectClass) {
argumentIsNotNull(valueObjectClass);
clientsClassDefinitions.add(new ValueObjectDefinition(valueObjectClass));
registerClassDefinition(new ValueObjectDefinition(valueObjectClass));
return this;
}

Expand Down Expand Up @@ -220,7 +225,7 @@ public JaversBuilder registerValueObject(Class<?> valueObjectClass) {
*/
public JaversBuilder registerEntity(EntityDefinition entityDefinition){
argumentIsNotNull(entityDefinition);
clientsClassDefinitions.add(entityDefinition);
registerClassDefinition(entityDefinition);
return this;
}

Expand Down Expand Up @@ -249,13 +254,13 @@ public JaversBuilder registerEntity(EntityDefinition entityDefinition){
*/
public JaversBuilder registerValueObject(ValueObjectDefinition valueObjectDefinition) {
argumentIsNotNull(valueObjectDefinition);
clientsClassDefinitions.add(valueObjectDefinition);
registerClassDefinition(valueObjectDefinition);
return this;
}

/**
* Comma separated list of packages.<br/>
* Allows you to register all your classes with &#64;{@link TypeName} annotation
* Allows you to registerClassDefinition all your classes with &#64;{@link TypeName} annotation
* in order to use them in all kinds of JQL queries<br/>
* (without getting TYPE_NAME_NOT_FOUND exception).
*
Expand All @@ -269,7 +274,7 @@ public JaversBuilder withPackagesToScan(String packagesToScan) {

long start = System.currentTimeMillis();
logger.info("scanning package(s): {}", packagesToScan);
List<Class<?>> scan = ReflectionUtil.findClasses(TypeName.class, packagesToScan.replaceAll(" ","").split(","));
List<Class<?>> scan = findClasses(TypeName.class, packagesToScan.replaceAll(" ","").split(","));
for (Class<?> c : scan) {
scanTypeName(c);
}
Expand Down Expand Up @@ -309,13 +314,13 @@ public JaversBuilder scanTypeName(Class userType){
*
* Values are compared using default {@link Object#equals(Object)}.
* If you don't want to use it,
* register a custom value comparator with {@link #registerValue(Class, CustomValueComparator)}.
* registerClassDefinition a custom value comparator with {@link #registerValue(Class, CustomValueComparator)}.
*
* @see <a href="http://javers.org/documentation/domain-configuration/#ValueType">http://javers.org/documentation/domain-configuration/#ValueType</a>
*/
public JaversBuilder registerValue(Class<?> valueClass) {
argumentIsNotNull(valueClass);
clientsClassDefinitions.add(new ValueDefinition(valueClass));
registerClassDefinition(new ValueDefinition(valueClass));
return this;
}

Expand Down Expand Up @@ -353,7 +358,81 @@ public JaversBuilder registerValue(Class<?> valueClass) {
*/
public <T> JaversBuilder registerValue(Class<T> valueClass, CustomValueComparator<T> customValueComparator) {
argumentsAreNotNull(valueClass, customValueComparator);
clientsClassDefinitions.add(new ValueDefinition(valueClass, customValueComparator));

if (!clientsClassDefinitions.containsKey(valueClass)){
registerClassDefinition(new ValueDefinition(valueClass));
}
ValueDefinition def = getClassDefinition(valueClass);
def.setCustomValueComparator(customValueComparator);

return this;
}

/**
* For complex <code>ValueType</code> classes that are used as Entity Id.
* <br/><br/>
*
* Registers a custom <code>toString</code> function that will be used for creating
* <code>GlobalId</code> for Entities,
* instead of default {@link ReflectionUtil#reflectiveToString(Object)}.
* <br/><br/>
*
* For example:
*
* <pre>
* class Entity {
* &#64;Id Point id
* String data
* }
*
* class Point {
* double x
* double y
*
* String myToString() {
* "("+ (int)x +"," +(int)y + ")"
* }
* }
*
* def "should use custom toString function for complex Id"(){
* given:
* Entity entity = new Entity(
* id: new Point(x: 1/3, y: 4/3))
*
* when: "default reflectiveToString function"
* def javers = JaversBuilder.javers().build()
* GlobalId id = javers.getTypeMapping(Entity).createIdFromInstance(entity)
*
* then:
* id.value() == "com.mypackage.Entity/0.3333333333,1.3333333333"
*
* when: "custom toString function"
* javers = JaversBuilder.javers()
* .registerValueWithCustomToString(Point, {it.myToString()}).build()
* id = javers.getTypeMapping(Entity).createIdFromInstance(entity)
*
* then:
* id.value() == "com.mypackage.Entity/(0,1)"
* }
* </pre>
*
* For <code>ValueType</code> you can register both
* custom <code>toString</code> function and <code>CustomValueComparator</code>.
*
* @param toString should return String value of a given object
* @see ValueType
* @see #registerValue(Class, CustomValueComparator)
* @since 3.7.6
*/
public <T> JaversBuilder registerValueWithCustomToString(Class<T> valueClass, Function<T, String> toString) {
argumentsAreNotNull(valueClass, toString);

if (!clientsClassDefinitions.containsKey(valueClass)){
registerClassDefinition(new ValueDefinition(valueClass));
}
ValueDefinition def = getClassDefinition(valueClass);
def.setToStringFunction((Function)toString);

return this;
}

Expand All @@ -367,7 +446,7 @@ public <T> JaversBuilder registerValue(Class<T> valueClass, CustomValueComparato
*/
public JaversBuilder registerIgnoredClass(Class<?> ignoredClass) {
argumentIsNotNull(ignoredClass);
clientsClassDefinitions.add(new IgnoredTypeDefinition(ignoredClass));
registerClassDefinition(new IgnoredTypeDefinition(ignoredClass));
return this;
}

Expand Down Expand Up @@ -532,7 +611,7 @@ public JaversBuilder withObjectAccessHook(ObjectAccessHook objectAccessHook) {
* @see CustomType
*/
public <T> JaversBuilder registerCustomComparator(CustomPropertyComparator<T, ?> comparator, Class<T> customType){
clientsClassDefinitions.add(new CustomDefinition(customType));
registerClassDefinition(new CustomDefinition(customType));
bindComponent(comparator, new CustomToNativeAppenderAdapter(comparator, customType));
return this;
}
Expand Down Expand Up @@ -571,7 +650,7 @@ public JaversBuilder withDateTimeProvider(DateProvider dateProvider) {

private void mapRegisteredClasses() {
TypeMapper typeMapper = typeMapper();
for (ClientsClassDefinition def : clientsClassDefinitions) {
for (ClientsClassDefinition def : clientsClassDefinitions.values()) {
typeMapper.registerClientsClass(def);
}
}
Expand Down Expand Up @@ -640,7 +719,7 @@ private void bootDateTimeProvider() {

private void bootRepository(){
if (repository == null){
logger.info("using fake InMemoryRepository, register actual implementation via JaversBuilder.registerJaversRepository()");
logger.info("using fake InMemoryRepository, registerClassDefinition actual implementation via JaversBuilder.registerJaversRepository()");
addModule(new InMemoryRepositoryModule(getContainer()));
repository = getContainerComponent(JaversRepository.class);
} else {
Expand All @@ -651,4 +730,13 @@ private void bootRepository(){
//JaversExtendedRepository can be created after users calls JaversBuilder.registerJaversRepository()
addComponent(JaversExtendedRepository.class);
}

private <T extends ClientsClassDefinition> T getClassDefinition(Class<?> baseJavaClass) {
return (T)clientsClassDefinitions.get(baseJavaClass);
}

private void registerClassDefinition(ClientsClassDefinition clientsClassDefinition) {
argumentIsNotNull(clientsClassDefinition);
clientsClassDefinitions.put(clientsClassDefinition.getBaseJavaClass(), clientsClassDefinition);
}
}
Expand Up @@ -3,7 +3,6 @@
import org.javers.core.diff.NodePair;
import org.javers.core.diff.changetype.ValueChange;
import org.javers.core.metamodel.type.*;
import static org.javers.common.reflection.ReflectionUtil.reflectiveToString;

/**
* @author bartosz walacik
Expand All @@ -25,11 +24,12 @@ public ValueChange calculateChanges(NodePair pair, JaversProperty property) {

//special treatment for EmbeddedId - could be ValueObjects without good equals() implementation
if (isIdProperty(pair, property)) {
if (property.getType().equals(reflectiveToString(leftValue),
reflectiveToString(rightValue))){
//For idProperty, only initial change is possible (from null to value).
//If we have values on both sides, we know that they have the same String representation
if (leftValue != null && rightValue != null) {
return null;
}
}else {
} else {
if (property.getType().equals(leftValue, rightValue)) {
return null;
}
Expand Down
Expand Up @@ -3,7 +3,6 @@
import org.javers.common.collections.Lists;
import org.javers.common.reflection.JaversMember;
import org.javers.core.metamodel.object.Cdo;
import org.javers.core.metamodel.object.CdoWrapper;
import org.javers.core.metamodel.object.UnboundedValueObjectId;
import org.javers.core.metamodel.property.Property;
import org.javers.core.metamodel.scanner.ClassScanner;
Expand Down Expand Up @@ -34,6 +33,6 @@ public Cdo createCdo(final CollectionWrapper wrapper, final Class<?> clazz) {
JaversProperty fixedJProperty = new JaversProperty(() -> typeMapper.getPropertyType(fixedProperty), fixedProperty);

ValueObjectType valueObject = new ValueObjectType(wrapper.getClass(), Lists.asList(fixedJProperty));
return new CdoWrapper(wrapper, new UnboundedValueObjectId(valueObject.getName()), valueObject);
return new LiveCdoWrapper(wrapper, new UnboundedValueObjectId(valueObject.getName()), valueObject);
}
}
@@ -0,0 +1,21 @@
package org.javers.core.graph;

import org.javers.core.metamodel.object.GlobalId;
import org.javers.core.metamodel.object.LiveCdo;
import org.javers.core.metamodel.type.ManagedType;

import java.util.function.Supplier;

class LazyCdoWrapper extends LiveCdo {
private final Supplier<?> cdoSupplier;

public LazyCdoWrapper(Supplier<?> cdoSupplier, GlobalId globalId, ManagedType managedType) {
super(globalId, managedType);
this.cdoSupplier = cdoSupplier;
}

@Override
protected Object wrappedCdo() {
return cdoSupplier.get();
}
}