contentful/contentful.java

Need to access TransformQuery.transform(CDAEntry entry)

Closed this issue · 1 comments

Bonjour,

In our codebase, we have some boring manual mapping functions like this one:

fun mapCDAEntryToEmployee(entry: CDAEntry): Employee {
    return Employee(
        id = entry.id(),
        firstName = entry.getField("firstName") ?: String.EMPTY,
        lastName = entry.getField("lastName") ?: String.EMPTY,
/// ...
    )
}

That's because we need to call that outside of a TransformQuery

And TransformQuery seems to be the only place where mapping from a CDAEntry to a POJO via annotations is available

private Object transform(CDAEntry entry) {
final Object result;
if (!customClassByContentTypeIdCache.containsKey(entry.contentType().id())) {
return entry;
}
final Class<?> type = customClassByContentTypeIdCache.get(entry.contentType().id());
if (instanceCache.containsKey(entry.id())) {
result = instanceCache.get(entry.id());
} else {
try {
result = type.newInstance();
} catch (Exception e) {
throw new IllegalStateException("Cannot transform entry " + entry + " to type "
+ type.getCanonicalName(), e);
}
instanceCache.put(entry.id(), result);
for (final Field field : type.getDeclaredFields()) {
final ContentfulField annotation = field.getAnnotation(ContentfulField.class);
if (annotation != null) {
transformFieldAnnotation(entry, result, field, annotation);
} else {
final ContentfulSystemField systemField =
field.getAnnotation(ContentfulSystemField.class);
if (systemField != null) {
transformSystemFieldAnnotation(entry, result, field, systemField);
}
}
}
}
return result;
}
private void transformFieldAnnotation(
CDAEntry entry,
Object result,
Field field,
ContentfulField annotation) {
final boolean wasAccessible = field.isAccessible();
field.setAccessible(true);
final String key;
if (annotation.value().isEmpty()) {
key = field.getName();
} else {
key = annotation.value();
}
final String locale;
if (annotation.locale().isEmpty()) {
locale = entry.defaultLocale;
} else {
locale = annotation.locale();
}
try {
final Object value = entry.getField(locale, key);
if (value instanceof CDAEntry) {
final CDAEntry fieldEntry = (CDAEntry) value;
if (!instanceCache.containsKey(fieldEntry.id())) {
transform(fieldEntry);
}
field.set(result, instanceCache.get(fieldEntry.id()));
} else if (value instanceof Collection) {
@SuppressWarnings("unchecked") final Collection<Object> collection = (Collection) value;
final ArrayList<Object> transformedList = new ArrayList<>(collection.size());
for (final Object element : collection) {
if (element instanceof CDAEntry) {
final CDAEntry collectionEntry = (CDAEntry) element;
if (customClassByContentTypeIdCache.containsKey(collectionEntry.contentType().id())) {
transformedList.add(transform(collectionEntry));
} else {
transformedList.add(element);
}
} else {
transformedList.add(element);
}
field.set(result, transformedList);
}
} else {
field.set(result, value);
}
} catch (IllegalAccessException e) {
throw new IllegalStateException("Cannot set custom field " + key + ".");
} finally {
field.setAccessible(wasAccessible);
}
}
private void transformSystemFieldAnnotation(CDAEntry entry, Object result, Field field,
ContentfulSystemField annotation) {
if (!field.isAccessible()) {
field.setAccessible(true);
}
final String key;
if (annotation.value().isEmpty()) {
key = field.getName();
} else {
key = annotation.value();
}
try {
field.set(result, entry.getAttribute(key));
} catch (IllegalAccessException e) {
throw new IllegalStateException("Cannot set custom system field " + key + ".");
}
}
}

Would it be possible to add a public API for that?

Hey @jmfayard ,
unfortunately, we don't have plans to make it a public API any time soon.