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

Reduce getter calls during fields mapping #347

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@ public MultiOccurrenceVariableRef(Type<?> type, String name) {
}

public String declareIterator() {
return declareIterator(getter());
}

public String declareIterator(String value) {
if (iteratorDeclared) {
throw new IllegalStateException("Iterator has already been declared");
}
Expand All @@ -76,7 +80,7 @@ public String declareIterator() {
} else if (isMap()) {
iterator = new EntrySetRef(this, name()).declareIterator();
} else {
iterator = "java.util.Iterator " + getIteratorName() + " = " + getter() + ".iterator()";
iterator = "java.util.Iterator " + getIteratorName() + " = " + value + ".iterator()";
}
iteratorDeclared = true;
return iterator;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,20 @@ public void debugField(FieldMap fieldMap, String msg) {
logDetails.append(msg);
}
}

public String optionallyMakeDestinationVariableAndGetValue(StringBuilder out, VariableRef destination, boolean getDestinationOnMapping){

if(!getDestinationOnMapping){
return "null";
}

if(shouldCaptureFieldContext){
addVariable(out, destination);
return destination.getGlobalUniqueName();
}

return destination.asWrapper();
}

public String fieldTag(FieldMap fieldMap) {
return "\n\t Field(" + fieldMap.getSource() + ", " + fieldMap.getDestination() + ") : ";
Expand Down Expand Up @@ -354,7 +368,11 @@ public String newObjectFromMapper(Type<?> sourceType, Type<?> destinationType) {
* from a mapper
*/
public String newObjectFromMapper(VariableRef source, Type<?> destinationType) {
return newObjectFromMapper(source.type(), destinationType) + "(" + source.asWrapper() + ", mappingContext)";
return newObjectFromMapper(source, source.asWrapper(), destinationType);
}

public String newObjectFromMapper(VariableRef source, String sourceValue, Type<?> destinationType) {
return newObjectFromMapper(source.type(), destinationType) + "(" + sourceValue + ", mappingContext)";
}

/**
Expand All @@ -374,12 +392,16 @@ public String usedType(VariableRef r) {
* default value in cases of primitive types
*/
public String newObject(VariableRef source, Type<?> destinationType) {
return newObject(source, source.asWrapper(), destinationType);
}

public String newObject(VariableRef source, String sourceValue, Type<?> destinationType) {
if (destinationType.isPrimitive()) {
return VariableRef.getDefaultValue(destinationType.getRawType());
} else if (destinationType.isString()) {
return "null";
} else {
return newObjectFromMapper(source, destinationType);
return newObjectFromMapper(source, sourceValue, destinationType);
}
}

Expand Down Expand Up @@ -499,9 +521,13 @@ public static String join(List<?> list, String separator) {
* variable ref, which should be a Map type
*/
public static VariableRef entrySetRef(VariableRef s) {
return entrySetRef(s, s.toString());
}

public static VariableRef entrySetRef(VariableRef s, String value) {
@SuppressWarnings("unchecked")
Type<?> sourceEntryType = TypeFactory.valueOf(Set.class, MapEntry.entryType((Type<? extends Map<Object, Object>>) s.type()));
return new VariableRef(sourceEntryType, s + ".entrySet()");
return new VariableRef(sourceEntryType, value + ".entrySet()");
}

/**
Expand Down Expand Up @@ -751,18 +777,25 @@ public String mapFields(FieldMap fieldMap, VariableRef source, VariableRef desti
source.setConverter(converter);

boolean getDestinationOnMapping = AbstractSpecification.shouldGetDestinationOnMapping(fieldMap, this);
addVariable(out, source);
String sourceValue = source.getGlobalUniqueName();
String destinationValue = optionallyMakeDestinationVariableAndGetValue(out, destination, getDestinationOnMapping);

if (shouldCaptureFieldContext) {
beginCaptureFieldContext(out, fieldMap, source, destination, getDestinationOnMapping);
beginCaptureFieldContext(out, fieldMap, sourceValue, destinationValue);
}
StringBuilder filterClosing = new StringBuilder();
VariableRef[] filteredProperties = applyFilters(source, destination, out, filterClosing, getDestinationOnMapping);
source = filteredProperties[0];
VariableRef[] filteredProperties = applyFilters(source, destination, out, filterClosing, sourceValue, destinationValue);

if(filteredProperties[0] != source){
source = filteredProperties[0];
sourceValue = source.asWrapper();
}
destination = filteredProperties[1];

for (Specification spec : codeGenerationStrategy.getSpecifications()) {
if (spec.appliesTo(fieldMap)) {
String code = spec.generateMappingCode(fieldMap, source, destination, this);
String code = spec.generateMappingCode(fieldMap, source, sourceValue, destination, this);
if (code == null || "".equals(code)) {
throw new IllegalStateException("empty code returned for spec " + spec + ", sourceProperty = " + source
+ ", destinationProperty = " + destination);
Expand All @@ -781,10 +814,15 @@ public String mapFields(FieldMap fieldMap, VariableRef source, VariableRef desti
return out.toString();
}

private void beginCaptureFieldContext(StringBuilder out, FieldMap fieldMap, VariableRef source, VariableRef dest, boolean getDestinationValueOnMapping) {
private void beginCaptureFieldContext(StringBuilder out, FieldMap fieldMap, String sourceValue, String destinationValue) {
out.append(format("mappingContext.beginMappingField(\"%s\", %s, %s, \"%s\", %s, %s);\n" + "try{\n",
escapeQuotes(fieldMap.getSource().getExpression()), usedType(fieldMap.getAType()), source.asWrapper(),
escapeQuotes(fieldMap.getDestination().getExpression()), usedType(fieldMap.getBType()), (getDestinationValueOnMapping)?dest.asWrapper():"null"));
escapeQuotes(fieldMap.getSource().getExpression()), usedType(fieldMap.getAType()), sourceValue,
escapeQuotes(fieldMap.getDestination().getExpression()), usedType(fieldMap.getBType()), destinationValue));
}

public void addVariable(StringBuilder out, VariableRef variable){
String sourceVariableType = variable.isPrimitive()? variable.wrapperTypeName() : variable.typeName();
out.append(sourceVariableType).append(" ").append(variable.getGlobalUniqueName()).append(" = ").append(variable.asWrapper()).append(";\n");
}

private void endCaptureFieldContext(StringBuilder out) {
Expand All @@ -794,36 +832,42 @@ private void endCaptureFieldContext(StringBuilder out) {
private String escapeQuotes(String string) {
return string.replaceAll("(?<!\\\\)\"", "\\\\\"");
}

public VariableRef[] applyFilters(VariableRef sourceProperty, VariableRef destinationProperty, StringBuilder out, StringBuilder closing, boolean getDestinationOnMapping) {
return applyFilters(sourceProperty, destinationProperty, out, closing, sourceProperty.asWrapper(), (getDestinationOnMapping)?destinationProperty.asWrapper():"null");
}

public VariableRef[] applyFilters(VariableRef sourceProperty, VariableRef destinationProperty, StringBuilder out, StringBuilder closing,
String sourceValue, String destinationValue) {
/*
* TODO: need code which collects all of the applicable filters and adds
* them into an aggregate filter object
*/
Filter<Object, Object> filter = getFilter(sourceProperty, destinationProperty);
if (filter != null) {

if (destinationProperty.isNestedProperty()) {
out.append("if (");
out.append(format("(%s && %s.shouldMap(%s, \"%s\", %s, %s, \"%s\", %s, mappingContext))", destinationProperty.pathNotNull(),
usedFilter(filter), usedType(sourceProperty.type()), varPath(sourceProperty), sourceProperty.asWrapper(),
usedType(destinationProperty.type()), varPath(destinationProperty), (getDestinationOnMapping)?destinationProperty.asWrapper():"null"));
usedFilter(filter), usedType(sourceProperty.type()), varPath(sourceProperty), sourceValue,
usedType(destinationProperty.type()), varPath(destinationProperty), destinationValue));

out.append(" || ");

out.append(format("(%s && %s.shouldMap(%s, \"%s\", %s, %s, \"%s\", null, mappingContext))", destinationProperty.pathNull(),
usedFilter(filter), usedType(sourceProperty.type()), varPath(sourceProperty), sourceProperty.asWrapper(),
usedType(destinationProperty.type()), varPath(destinationProperty)));
usedFilter(filter), usedType(sourceProperty.type()), varPath(sourceProperty), sourceValue,
usedType(destinationProperty.type()), varPath(destinationProperty)));

out.append(") {");
} else {
out.append(format("if (%s.shouldMap(%s, \"%s\", %s, %s, \"%s\", %s, mappingContext)) {", usedFilter(filter),
usedType(sourceProperty.type()), varPath(sourceProperty), sourceProperty.asWrapper(),
usedType(destinationProperty.type()), varPath(destinationProperty), (getDestinationOnMapping)?destinationProperty.asWrapper():"null"));
usedType(sourceProperty.type()), varPath(sourceProperty), sourceValue,
usedType(destinationProperty.type()), varPath(destinationProperty), destinationValue));
}

sourceProperty = getSourceFilter(sourceProperty, destinationProperty, filter);
destinationProperty = getDestFilter(sourceProperty, destinationProperty, filter);

// need to set source property
closing.insert(0, "\n}\n");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,20 +31,19 @@
public interface Specification extends BaseSpecification {

void setMapperFactory(MapperFactory mapperFactory);

/**
* Generates code for a boolean equality test between the two variable types,
* where are potentially unrelated.
*
*
* @param source
* @param destination
* @param code
* @return the code snippet which represents a true|false statement describing
* whether the two types should be considered 'equal'
*/
String generateEqualityTestCode(FieldMap fieldMap, VariableRef source, VariableRef destination, SourceCodeContext code);



/**
* Generates code to map the provided field map
*
Expand All @@ -55,5 +54,10 @@ public interface Specification extends BaseSpecification {
* @return the code snippet which represents mapping from the source to destination
* property
*/
String generateMappingCode(FieldMap fieldMap, VariableRef source, VariableRef destination, SourceCodeContext code);
default String generateMappingCode(FieldMap fieldMap, VariableRef source, VariableRef destination, SourceCodeContext code){
return generateMappingCode(fieldMap, source, source.toString(), destination, code);
}

String generateMappingCode(FieldMap fieldMap, VariableRef source, String sourceValue, VariableRef destination, SourceCodeContext code);

}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;

import ma.glasnost.orika.Converter;
import ma.glasnost.orika.Filter;
Expand All @@ -52,6 +53,7 @@
*/
public class VariableRef {

private static final AtomicLong NEXT_GLOBAL_UNIQUE_ID = new AtomicLong(0L);
private static final Set<Class<?>> OPTIONAL_CLASSES = Collections.newSetFromMap(new ConcurrentHashMap<Class<?>, Boolean>());
static {
try {
Expand All @@ -65,7 +67,8 @@ public class VariableRef {
// No Guava Optional...
}
}


private final String globalUniqueName = "$"+Long.toHexString(NEXT_GLOBAL_UNIQUE_ID.getAndIncrement());
protected String name;
private Property property;
private VariableRef owner;
Expand Down Expand Up @@ -94,7 +97,18 @@ public VariableRef(Type<?> type, String name) {
this.nullPossible = !isPrimitive();
this.nullPathPossible = isNestedProperty();
}


public String getGlobalUniqueName() {
return globalUniqueName;
}

public String toRawValue(String value){
if (isPrimitive()) {
return "(" + "(" + rawType() + ")" + value + ")";
}
return value;
}

public void setConverter(Converter<?, ?> converter) {
this.converter = converter;
}
Expand Down Expand Up @@ -296,8 +310,12 @@ public String assignIfPossible(String value, Object... replacements) {
* @return
*/
public String assignIfPossible(VariableRef value) {
return assignIfPossible(value, value.toString());
}

public String assignIfPossible(VariableRef value, String castValue) {
if (setter() != null) {
return format(setter(), cast(value));
return format(setter(), cast(value, castValue));
} else {
return "";
}
Expand All @@ -311,8 +329,11 @@ public String assignIfPossible(VariableRef value) {
* @return
*/
public String assign(VariableRef value) {
return assign(value, value.toString());
}

public String assign(VariableRef value, String expr) {
if (setter() != null) {
String expr = value.toString();
if (value.type().isPrimitive() && type.isPrimitiveWrapper()) {
String wrapperClass = ClassUtil.getWrapperType(rawType()).getCanonicalName();
expr = format("(%s) %s.valueOf(%s)", wrapperClass, wrapperClass, expr);
Expand All @@ -336,7 +357,11 @@ public String assign(VariableRef value) {
}

public String cast(VariableRef ref) {
return cast(ref, type());
return cast(ref, ref.toString());
}

public String cast(VariableRef ref, String castValue) {
return cast(ref, type(), castValue);
}

/**
Expand Down Expand Up @@ -387,14 +412,17 @@ protected static String cast(String value, Type<?> type) {
* @return
*/
protected static String cast(VariableRef value, Type<?> type) {
String castValue = value.toString();
return cast(value, type, value.toString());
}

protected static String cast(VariableRef value, Type<?> type, String castValue) {
String typeName = type.getCanonicalName();

if (type.isPrimitive()) {
if (value.isWrapper()) {
castValue = format("%s.%sValue()", castValue, type);
} else if (Character.TYPE == type.getRawType() && value.type().isString()) {
castValue = format("%s.charAt(0)", value);
} else if (Character.TYPE == type.getRawType() && value.type().isString()) {
castValue = format("%s.charAt(0)", castValue);
} else if (!value.isPrimitive()) {
castValue = format("%s.valueOf(\"\"+%s).%sValue()", type.getWrapperType().getCanonicalName(), castValue, typeName);
}
Expand Down Expand Up @@ -530,10 +558,17 @@ private static String unwrap(String expression) {
}

private static String isNull(Property property, String name) {
if (property == null) {
return name + " == null";
}
return isNull(property, name, getGetter(property, name));
}

private static String isNull(Property property, String name, String value) {
if (property == null) {
return name + " == null";
} else {
String getterNull = getGetter(property, name) + " == null";
String getterNull = value + " == null";
if (property.isListElement()) {
return "(" + unwrap(getGetter(property, name)) + ".size() <= " + property.getName().replaceAll("[\\[\\]]", "") + " || "
+ getterNull + ")";
Expand Down Expand Up @@ -576,10 +611,14 @@ private String notNullIncludingPath() {

return path.toString();
}

public String notNull() {
return notNull(isNullPathPossible());
}

public String notNull(String value) {
return notNull(isNullPathPossible(), value);
}

public String notNull(boolean includePath) {
if (includePath) {
Expand All @@ -588,14 +627,30 @@ public String notNull(boolean includePath) {
return format("!(%s)", isNull(property, name));
}
}

public String notNull(boolean includePath, String value) {
if (includePath) {
return notNullIncludingPath();
} else {
return format("!(%s)", isNull(property, name, value));
}
}

public String ifNotNull() {
return ifNotNull(isNullPathPossible());
}


public String ifNotNull(String value) {
return ifNotNull(isNullPathPossible(), value);
}

public String ifNotNull(boolean includePath) {
return "if ( " + notNull(includePath) + ")";
}

public String ifNotNull(boolean includePath, String value) {
return "if ( " + notNull(includePath, value) + ")";
}

public String ifNull() {
return "if ( " + isNull() + ") ";
Expand Down
Loading