Skip to content

Commit

Permalink
Merge pull request #86 from MikeDombo/no-static
Browse files Browse the repository at this point in the history
Add option for serializing and deserializing non-final static fields, disabled by default
  • Loading branch information
cowtowncoder authored May 14, 2021
2 parents e69b3cc + ecfc4a1 commit bbab957
Show file tree
Hide file tree
Showing 6 changed files with 120 additions and 69 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -31,20 +31,22 @@ public class AnnotationBasedIntrospector
* Visibility settings to use for auto-detecting accessors.
*/
protected final JsonAutoDetect.Value _visibility;

// // // State (collected properties, related)

protected final Map<String, APropBuilder> _props = new HashMap<String, APropBuilder>();

// // // State only for deserialization:

protected Set<String> _ignorableNames;
protected int _features;

protected AnnotationBasedIntrospector(Class<?> type, boolean serialization,
JsonAutoDetect.Value visibility) {
JsonAutoDetect.Value visibility, int features) {
_type = type;
_forSerialization = serialization;
_ignorableNames = serialization ? null : new HashSet<String>();
_features = features;

// First things first: find possible `@JsonAutoDetect` to override
// default visibility settings
Expand All @@ -58,13 +60,13 @@ protected AnnotationBasedIntrospector(Class<?> type, boolean serialization,

public static POJODefinition pojoDefinitionForDeserialization(JSONReader r,
Class<?> pojoType, JsonAutoDetect.Value visibility) {
return new AnnotationBasedIntrospector(pojoType, false, visibility)
return new AnnotationBasedIntrospector(pojoType, false, visibility, r.features())
.introspectDefinition();
}

public static POJODefinition pojoDefinitionForSerialization(JSONWriter w,
Class<?> pojoType, JsonAutoDetect.Value visibility) {
return new AnnotationBasedIntrospector(pojoType, true, visibility)
return new AnnotationBasedIntrospector(pojoType, true, visibility, w.features())
.introspectDefinition();
}

Expand Down Expand Up @@ -235,9 +237,9 @@ protected void _findFields(final Class<?> currType)

// then get fields from within class itself
for (Field f : currType.getDeclaredFields()) {
// Does not include static fields, but there are couple of things we do
// not include regardless:
if (f.isEnumConstant() || f.isSynthetic()) {
// skip static fields and synthetic fields except for enum constants
if ((JSON.Feature.INCLUDE_STATIC_FIELDS.isDisabled(_features) && Modifier.isStatic(f.getModifiers())
&& !f.isEnumConstant()) || f.isSynthetic()) {
continue;
}
// otherwise, first things first; explicit ignoral?
Expand Down Expand Up @@ -284,7 +286,7 @@ protected void _findMethods(final Class<?> currType)
final int flags = m.getModifiers();
// 13-Jun-2015, tatu: Skip synthetic, bridge methods altogether, for now
// at least (add more complex handling only if absolutely necessary)
if (Modifier.isStatic(flags)
if ((JSON.Feature.INCLUDE_STATIC_FIELDS.isDisabled(_features) && Modifier.isStatic(flags))
|| m.isSynthetic() || m.isBridge()) {
continue;
}
Expand Down Expand Up @@ -350,7 +352,7 @@ protected void _checkGetterMethod(Method m)
acc = APropAccessor.createVisible(implName, m);
} else {
acc = APropAccessor.createExplicit(explName, m);
}
}
}
}
_propBuilder(implName).getter = acc;
Expand Down Expand Up @@ -397,7 +399,7 @@ protected void _checkSetterMethod(Method m)
acc = APropAccessor.createVisible(implName, m);
} else {
acc = APropAccessor.createExplicit(explName, m);
}
}
}
}
_propBuilder(implName).setter = acc;
Expand All @@ -410,9 +412,10 @@ protected void _checkSetterMethod(Method m)
*/

protected boolean _isFieldVisible(Field f) {
// Consider transient to be non-visible
// Consider transient and static-final to be non-visible
// TODO: (maybe?) final
return !Modifier.isTransient(f.getModifiers())
return !(Modifier.isFinal(f.getModifiers()) && Modifier.isStatic(f.getModifiers()))
&& !Modifier.isTransient(f.getModifiers())
&& _visibility.getFieldVisibility().isVisible(f);
}

Expand All @@ -426,7 +429,7 @@ protected boolean _isGetterVisible(Method m, boolean isIsGetter) {
protected boolean _isSetterVisible(Method m) {
return _visibility.getSetterVisibility().isVisible(m);
}

/*
/**********************************************************************
/* Internal methods, annotation introspection
Expand All @@ -449,7 +452,7 @@ protected String _findExplicitName(AnnotatedElement m) {
* Lookup method for finding possible annotated order of property names
* for the type this introspector is to introspect
*
* @return List of property names that defines order (possibly partial); if
* @return List of property names that defines order (possibly partial); if
* none, empty List (but never null)
*/
protected List<String> _findNameSortOrder() {
Expand All @@ -465,7 +468,7 @@ protected List<String> _findNameSortOrder() {
* for the type this introspector is to introspect that should be ignored
* (both for serialization and deserialization).
*
* @return List of property names that defines order (possibly partial); if
* @return List of property names that defines order (possibly partial); if
* none, empty List (but never null)
*/
protected Collection<String> _findIgnorableNames() {
Expand All @@ -480,13 +483,13 @@ protected Collection<String> _findIgnorableNames() {
protected <ANN extends Annotation> ANN _find(AnnotatedElement elem, Class<ANN> annotationType) {
return elem.getAnnotation(annotationType);
}

/*
/**********************************************************************
/* Internal methods, other
/**********************************************************************
*/

protected APropBuilder _propBuilder(String name) {
APropBuilder b = _props.get(name);
if (b == null) {
Expand Down Expand Up @@ -546,7 +549,7 @@ protected static String _decap(String name) {
/* Helper classes
/**********************************************************************
*/

protected static class APropBuilder
implements Comparable<APropBuilder>
{
Expand Down Expand Up @@ -615,7 +618,7 @@ private static <A extends AccessibleObject> APropAccessor<A> _merge(APropAccesso
// should be fine to take first one
return a1;
}

public APropBuilder withName(String newName) {
APropBuilder newB = new APropBuilder(this, newName);
newB.field = field;
Expand Down Expand Up @@ -676,7 +679,7 @@ private static Set<String> _collectAliases(APropAccessor<?> acc, Set<String> col
}
return collectedAliases;
}

private String _firstExplicit(APropAccessor<?> acc1,
APropAccessor<?> acc2,
APropAccessor<?> acc3) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
public class BasicIgnoralTest extends ASTestBase
{
static class XY {
public static int DEFAULT = 123;
public static final int DEFAULT_FINAL = 123;
@JsonIgnore
public int x;
public int y;
Expand Down Expand Up @@ -42,13 +44,16 @@ public XYZ(int x, int y, int z) {
}

private final JSON JSON_WITH_ANNO = jsonWithAnnotationSupport();
private final JSON JSON_WITH_ANNO_WITH_STATIC =
JSON.builder().register(JacksonAnnotationExtension.std).enable(JSON.Feature.INCLUDE_STATIC_FIELDS).build();
private final JSON JSON_WITH_STATIC = JSON.builder().enable(JSON.Feature.INCLUDE_STATIC_FIELDS).build();

/*
/**********************************************************************
/* Tests for basic @JsonIgnore
/**********************************************************************
*/

public void testPropertyIgnoralOnSerialize() throws Exception
{
final XY input = new XY(1, 2);
Expand All @@ -60,26 +65,41 @@ public void testPropertyIgnoralOnSerialize() throws Exception

// and ensure no leakage to default one:
assertEquals(a2q("{'x':1,'y':2}"), JSON.std.asString(input));

// Verify serialization of static fields when the INCLUDE_STATIC_FIELDS option is enabled
assertEquals(a2q("{'DEFAULT':123,'x':1,'y':2}"), JSON_WITH_STATIC.asString(input));
assertEquals(a2q("{'DEFAULT':123,'y':2}"), JSON_WITH_ANNO_WITH_STATIC.asString(input));
}

public void testPropertyIgnoralOnDeserialize() throws Exception
{
final String json = a2q("{'x':1,'y':2}");
final String json = a2q("{'DEFAULT':125,'x':1,'y':2}");

// default: no filtering by ignorals
XY result = JSON.std.beanFrom(XY.class, json);
assertEquals(1, result.x);
assertEquals(2, result.y);
assertEquals(XY.DEFAULT_FINAL, XY.DEFAULT);

// but with ignore, should skip
result = JSON_WITH_ANNO.beanFrom(XY.class, json);
assertEquals(0, result.x);
assertEquals(2, result.y);
assertEquals(XY.DEFAULT_FINAL, XY.DEFAULT);

// and once again verify non-stickiness
result = JSON.std.beanFrom(XY.class, json);
assertEquals(1, result.x);
assertEquals(2, result.y);
assertEquals(XY.DEFAULT_FINAL, XY.DEFAULT);

// Verify setting static field from serialized data when the INCLUDE_STATIC_FIELDS option is enabled
JSON_WITH_STATIC.beanFrom(XY.class, json);
assertEquals(125, XY.DEFAULT);
XY.DEFAULT = XY.DEFAULT_FINAL;
JSON_WITH_ANNO_WITH_STATIC.beanFrom(XY.class, json);
assertEquals(125, XY.DEFAULT);
XY.DEFAULT = XY.DEFAULT_FINAL;
}

public void testPropertyIgnoreWithUnknown() throws Exception
Expand Down
Loading

0 comments on commit bbab957

Please sign in to comment.