com.fasterxml.jackson.module.afterburner.ser.SerializerModifier Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jackson-module-afterburner Show documentation
Show all versions of jackson-module-afterburner Show documentation
Jackson (https://github.com/FasterXML/jackson) extension module
used to enhance performance using bytecode generation to replace use of Reflection for
field access and method calls
package com.fasterxml.jackson.module.afterburner.ser;
import java.lang.reflect.Member;
import java.lang.reflect.Modifier;
import java.util.*;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.introspect.AnnotatedMember;
import com.fasterxml.jackson.databind.introspect.AnnotatedMethod;
import com.fasterxml.jackson.databind.ser.*;
import com.fasterxml.jackson.module.afterburner.util.MyClassLoader;
public class SerializerModifier extends BeanSerializerModifier
implements java.io.Serializable // since 2.11.1
{
private static final long serialVersionUID = 1L; // since 2.11.1
/**
* Class loader to use for generated classes; if null, will try to
* use class loader of the target class.
*/
protected final MyClassLoader _classLoader;
public SerializerModifier(ClassLoader cl)
{
// If we were given parent class loader explicitly, use that:
_classLoader = (cl == null) ? null : new MyClassLoader(cl, false);
}
@Override
public List changeProperties(SerializationConfig config,
BeanDescription beanDesc, List beanProperties)
{
final Class> beanClass = beanDesc.getBeanClass();
// [Issue#21]: Can't force access to sealed packages, or anything within "java."
// namespace. (how about javax.?)
if (!MyClassLoader.canAddClassInPackageOf(beanClass)) {
return beanProperties;
}
/* Hmmh. Can we access stuff from private classes?
* Possibly, if we can use parent class loader.
* (should probably skip all non-public?)
*/
if (_classLoader != null) {
if (Modifier.isPrivate(beanClass.getModifiers())) {
return beanProperties;
}
}
PropertyAccessorCollector collector = findProperties(beanClass, config, beanProperties);
if (collector.isEmpty()) {
return beanProperties;
}
// if we had a match, need to materialize
BeanPropertyAccessor acc = null;
// and then link accessors to bean property writers:
ListIterator it = beanProperties.listIterator();
while (it.hasNext()) {
BeanPropertyWriter bpw = it.next();
if (bpw instanceof OptimizedBeanPropertyWriter>) {
if (acc == null) {
acc = collector.findAccessor(_classLoader);
}
it.set(((OptimizedBeanPropertyWriter>) bpw).withAccessor(acc));
}
}
return beanProperties;
}
protected PropertyAccessorCollector findProperties(Class> beanClass,
SerializationConfig config, List beanProperties)
{
PropertyAccessorCollector collector = new PropertyAccessorCollector(beanClass);
ListIterator it = beanProperties.listIterator();
while (it.hasNext()) {
BeanPropertyWriter bpw = it.next();
AnnotatedMember member = bpw.getMember();
Member jdkMember = member.getMember();
// 11-Sep-2015, tatu: Let's skip virtual members (related to #57)
if (jdkMember == null) {
continue;
}
// We can't access private fields or methods, skip:
if (Modifier.isPrivate(jdkMember.getModifiers())) {
continue;
}
// (although, interestingly enough, can seem to access private classes...)
// 30-Jul-2012, tatu: [#6]: Needs to skip custom serializers, if any.
if (bpw.hasSerializer()) {
if (!SerializerUtil.isDefaultSerializer(bpw.getSerializer())) {
continue;
}
}
// [#9]: also skip unwrapping stuff...
if (bpw.isUnwrapping()) {
continue;
}
// [#51]: and any sub-classes as well
/* 04-Mar-2015, tatu: This might be too restrictive, as core databind has some
* other sub-classes; if this becomes problematic may start using annotation
* to indicate "standard" implementations. But for now this solves the issue.
*/
if (bpw.getClass() != BeanPropertyWriter.class) {
continue;
}
// 11-Apr-2016, tatu: Actually we have to consider actual physical type
// of accessor, not just logical type, see [afterburner#4]; generic
// types
// Class> type = bpw.getType().getRawClass();
Class> type = bpw.getMember().getRawType();
boolean isMethod = (member instanceof AnnotatedMethod);
if (type.isPrimitive()) {
if (type == Integer.TYPE) {
if (isMethod) {
it.set(collector.addIntGetter(bpw));
} else {
it.set(collector.addIntField(bpw));
}
} else if (type == Long.TYPE) {
if (isMethod) {
it.set(collector.addLongGetter(bpw));
} else {
it.set(collector.addLongField(bpw));
}
} else if (type == Boolean.TYPE) {
if (isMethod) {
it.set(collector.addBooleanGetter(bpw));
} else {
it.set(collector.addBooleanField(bpw));
}
}
} else {
if (type == String.class) {
if (isMethod) {
it.set(collector.addStringGetter(bpw));
} else {
it.set(collector.addStringField(bpw));
}
} else { // any other Object types; we can at least call accessor
if (isMethod) {
it.set(collector.addObjectGetter(bpw));
} else {
it.set(collector.addObjectField(bpw));
}
}
}
}
return collector;
}
}