jackson-module-scala
jackson-module-scala copied to clipboard
Empty JSON when serializing from Scala class with @JsonFilter annotation
Does this module support using @JsonFilter within a Scala class to filter out attributes? When I add it to a getter on my Scala class, the resulting object in the JSON is empty: {}.
I'm using an ObjectMapper like this to try and serialize a Product Java object. @JsonFilter is necessary to filter out instances where Product or stuff that's related to it references itself.
private static final ObjectMapper JSON_MAPPER = new ObjectMapper()
.registerModule(new DefaultScalaModule());
private static final FilterProvider JSON_SERIALIZATION_FILTERS = new SimpleFilterProvider()
.addFilter(
"addOnProduct",
SimpleBeanPropertyFilter.filterOutAllExcept(Sets.newHashSet("id", "price"))
);
...
JSON_MAPPER.writer(JSON_SERIALIZATION_FILTERS).writeValue(response.getOutputStream(), product);
Product.java has
Trim getTrim()
Trim.scala has a Trim case class with this:
@JsonFilter("addOnProduct")
def product: Option[Product] = productCode map(Product.of _)
No one has done any work to explicitly support this use case in the module; if it doesn't work, it's because something in the Scala specific logic is suppressing what Jackson would do normally, so I'll have to take a look.
If you have the time, a more complete test case, preferably as a single file, would be helpful in getting to the root of the issue. Otherwise, I'll dig into the issue as time allows.
Thanks. When I can I'll certainly try to make a single file test case (or maybe 2 files with 1 Java and 1 Scala). Just wanted to check to see if it should work first, but it sounds like the answer the answer is maybe until proven otherwise :)
Just adding some more data as I've been testing in case. Unfortunately, not a test case yet though.
I downgraded to Jackson 2.5.4 because my property names were getting named wrong with 2.6.0 when I registered jackson-module-scala with my ObjectMapper(). Some of the names had get in them (but not all) on 2.6.0.
I tried @JsonFilter again with 2.5.4 and the following filter:
.addFilter(
"addOnProduct",
SimpleBeanPropertyFilter.filterOutAllExcept(Sets.newHashSet(
"id", "price", "syncBehavior",
// For debugging to see if this would work (shouldn't be needed and it didn't work)
"getPrice", "getSyncBehavior"
))
);
What's weird is that this time, the nested product wasn't empty, but it didn't have all the filtered attributes. It only had id and not the other 2 I was looking for. I tried naming them by their methods just in case also but that yielded the same result.
I tried using a different filter and did get the right attributes so the behavior is fairly surprising. I realize there's not enough to go off of here, so I'll post a test case when I can but it might be a little bit, since I have a workaround in place that just returns a map of the few attributes I want for now.
Sounds good. FWIW, 2.6.0 was unfortunately released incorrectly, and Maven doesn't have a way for us to mark the release as invalid. For the Scala module only, 2.6.0-1 is available as as patch release.
Thanks. I was using that patch release. On Jul 27, 2015 6:31 PM, "Christopher Currie" [email protected] wrote:
Sounds good. FWIW, 2.6.0 was unfortunately released incorrectly, and Maven doesn't have a way for us to mark the release as invalid. For the Scala module only, 2.6.0-1 is available as as patch release.
— Reply to this email directly or view it on GitHub https://github.com/FasterXML/jackson-module-scala/issues/217#issuecomment-125401147 .
As @christophercurrie said, filtering should work in general (since it is implemented by jackson-databind via standard property handling), but that it is possible that perhaps some state or configuration is not properly passed. One relatively common problem is the fragility of constructors, so that addition of new constructors to pass existing configuration during construction of (de)serializers may cause dropping of configuration state with new versions -- I do not have a good solution for this problem unfortunately, except for more testing coverage, which over time will help catch more and more potential regression problems.
Just following up, I haven't had time to look at the filtering issue, but I am also concerned about the property naming issue you mentioned. If 2.6.1 isn't naming properties the same way as 2.5.4, then I need to track that regression as well. Can you re-confirm this with 2.6.1, and if it's still a problem, open another issue?
Hi @christophercurrie. Thanks for following up. I've been pretty swamped so in light of hacking around my issues and downgrading with success, I haven't had much time to look into things. However, I just took a few minutes to try updating to 2.6.1 from 2.5.4 and I have the same issue as before where some names were prefixed with get.
I've created #224 to track this.
I did a quick peek at adding back a filter too and still had empty properties. I sort of feel like I'm doing something wrong, but I've worked around in one case by making an intermediate map to return stuff, and in another case, I duplicated my filter config somewhere else and it worked.
I was attempting to share this globally, but for some reason my filter wasn't working:
public class Product extends AbstractSurface implements Comparable<Product> {
...
public static final FilterProvider JSON_SERIALIZATION_FILTERS = new SimpleFilterProvider()
.addFilter("format", SimpleBeanPropertyFilter.serializeAllExcept())
.addFilter("checkout",
SimpleBeanPropertyFilter.filterOutAllExcept(Sets.newHashSet(
"shortTitle", "smallThumbnailUrl", "quantityInSet", "maxQuantity", "minQuantity", "qtyUnits",
"format", "mailAndMessage"
))
).addFilter(
"relatedProduct",
SimpleBeanPropertyFilter.filterOutAllExcept(Sets.newHashSet(
"id", "seoUrl", "smallThumbnailUrl", "hugeImageUrl",
"primaryDesignerHex", "shortTitle"
))
).addFilter(
"addOnProduct",
SimpleBeanPropertyFilter.filterOutAllExcept(Sets.newHashSet(
"id", "defaultPrice", "quantitySyncBehavior", "getDefaultPrice", "getQuantitySyncBehavior"
))
);
...
}
Instead, I copy/pasted the filter I needed at the time in another class and it worked as expected:
// For some reason using the definition in Product.java doesn't work here, but redeclaring this fixes it
private static final SimpleFilterProvider CHECKOUT_FILTER = new SimpleFilterProvider()
.addFilter("format", SimpleBeanPropertyFilter.filterOutAllExcept("name"))
.addFilter("checkout",
SimpleBeanPropertyFilter.filterOutAllExcept(Sets.newHashSet(
"shortTitle", "smallThumbnailUrl", "quantityInSet", "maxQuantity", "minQuantity", "qtyUnits",
"format", "mailAndMessage"
))
);
public static String stringify(final Object o) {
try {
return Strings.JSON_MAPPER.writer(CHECKOUT_FILTER).writeValueAsString(o);
} catch (final JsonProcessingException e) {
...
}
}
In the above, specifically, I copied the filters I needed into a new provider, and they worked vs reusing Product.JSON_SERIALIZATION_FILTERS didn't work. This was in 2.5.4.
I feel like I'm probably doing something something wrong here, but alas, things are running with my workarounds so no big deal for me right now.