思路
java
"Views" in this context mean ability to define subsets of logical properties (things accessed via getters or fields) to serialize. Views are defined statically (using annotations), but view to use for serialization is chosen dynamically (per serialization).
git
「Views」,在這個語境中,意思是爲將要序列化的邏輯屬性(經過get方法或者字段獲取到的)定義一個子集。views是經過註解(annotations)來靜態定義的,可是使用的時候是動態選擇的(每一個須要序列化的地方本身選擇使用哪些views)
github
設計
json
Views themselves are identified by using Classes, instead of Strings (or dedicated objects). Reasons:app
views是使用類來定義的,而不是使用字符串,或者其它某些特定的實例。緣由是:less
With classes, can use inheritance to naturally (?) represent View hierarchies (if a field is part of a View, it'll be also part of parent view)ide
使用類,就可使用繼承來更加天然的展現views的結構(若是一個字段是某個view的一部分,那麼它也是父級view的一部分)this
Classes can be used as annotation values: Enums not (Enums would have been one other obvious possibility) spa
類能夠用做註解中的值,而枚舉不能夠(枚舉也是另外一個可能用做view的設計)
設計
For future extensibility, classes can also be annotated if need be (no plans for such annotations yet)
考慮將來的擴展性,若是有必要的話,(用做vies定義的)類自己也能夠被打上註解(不過不在現有標籤的計劃中)
View membership defined using annotations: specify which view(s)property will be included in. If no view annotation, assumed to mean View identified by Object.class: that is, included in all views
咱們是這樣定義視圖註解的使用方式的:爲某個屬性標記上某個註解,標示這個屬性將被包含在(最終的json字符串之)內。若是某個屬性上沒有任何註解,則認爲它被標記爲「Object.class"的視圖,並會被包含在全部視圖中。
View to use for serialization (and with 2.0, deserialization) is specified dynamically; active view is a property of SerializationConfig (and DeserializationConfig). Conceptually defaults to Object.class; as if no View functionality was used at all.
在序列化爲json的過程當中(以及,在2.0中,還包括反序列化的過程),view是動態指定的。一個view是一個SerializationConfig (對反序列化來講則是DeserializationConfig)的一個屬性。這個屬性的默認值是Object.class,其功能和不使用view是同樣的。
Only single active view per serialization; but due to inheritance of Views, can combine Views via aggregation.
每次序列化都只能使用一個視圖;可是,考慮到視圖的繼承層次,能夠把多個視圖組合成一個。
All view membership inclusive, no need for exclusions? (however: could add an option to change default handling of 'unmarked' properties to mean "don't include unless specifically identified)
view的用法都是「包含在序列化結果」中的,沒有「排除在序列化結果以外」的語義。(不過,能夠增長一個選項來改變對「unmarked」屬性的默認處理方式——把它改爲「除非特別聲明,不然不把被標記屬性包含在序列化結果中」)
實現
1.4 implementation is used as follows.
1.4版的實現是這樣使用的。
First, defining views means declaring classes; you can reuse existing ones, or just create bogus classes -- they are just view identifiers with relationship information (child inherits view membership from parents):
首先,經過聲明一些類,來定義一堆view。你能夠重用現有的類或view,或者只建立一些「虛假的類」——所謂「虛假」是指,這些類只用來標識view以及view的依賴和關聯(例如,子view會繼承父view的信息)。如下是代碼:
// View definitions: class Views { static class Public { } static class ExtendedPublic extends PublicView { } static class Internal extends ExtendedPublicView { } } public class Bean { // Name is public @JsonView(Views.Public.class) String name; // Address semi-public @JsonView(Views.ExtendPublic.class) Address address; // SSN only for internal usage @JsonView(Views.Internal.class) SocialSecNumber ssn; }
With such view definitions, serialization would be done like so:
定義好這些view以後,序列化過程會這樣執行:
// short-cut: objectMapper.writeValueUsingView(out, beanInstance, ViewsPublic.class); // or fully exploded: objectMapper.getSerializationConfig().setSerializationView(Views.Public.class); // (note: can also pre-construct config object with 'mapper.copySerializationConfig'; reuse) objectMapper.writeValue(out, beanInstance); // will use active view set via Config // or, starting with 1.5, more convenient (ObjectWriter is reusable too) objectMapper.viewWriter(ViewsPublic.class).writeValue(out, beanInstance);
and result would only contain 'name', not 'address' or 'ssn'.
而且,最終結果會僅僅包含「name」,而沒有「address」或「ssn」。
NOTE: even if you only want to use "default" view -- that is, just exclude things that are only to be included in specific "full" view -- you DO need to enable View processing by specifying a view. If you do not have explicit "basic" view setting, just use Object.class.
注意:即便你只想使用「默認」view——也就是說,
By default all properties without explicit view definition are included in serialization. But starting with Jackson 1.5 you can change this default by:
objectMapper.configure(SerializationConfig.Feature.DEFAULT_VIEW_INCLUSION, false);
where false means that such properties are NOT included when enabling with a view. Default for this property is 'true'.
Although default implementation is not very customizable, underlying design does allow for implementing elaborate custom filtering, using alternative means of defining custom views. Here is how.
Depending on exactly how custom serialization is implemented, you may (or may not) need to enable view processing. If it is needed, you will just do something like:
ObjectWriter w = objectMapper.viewWriter(SomeClass.class); // 1.8 and prior ObjectWriter w = objectMapper.writerWithView(SomeClass.class); // 1.9 and above
which offers same set of writeValue (and writeValueAsString, writeValueAsBytes, ...) write methods and can be reused easily (or passed).
As of 2.0 this is also available for deserialization, like so:
ObjectReader r = objectMapper.readerWithView(SomeClass.class); // 2.0 and above
With 2.3 (of JAX-RS module) it is also possible to annotate JAX-RS resources like so:
public class Resource { @JsonView(Views.Public.class) @GET @Produces(MediaType.APPLICATION_JSON ) public List<Object> getElements() { ... return someResultList; } }
so that you need not try to configure active view via ObjectReader / ObjectWriter.
What you need to implement is a sub-class of org.codehaus.jackson.map.ser.BeanPropertyWriter: this is what standard JsonView does; and make SerializerFactory (usually BeanSerializerFactory) construct BeanSerializer with customized versions. Once this is done, you can control output during serialization as you want.
There is some sample code (src/sample/CustomSerializationView.java) to show how exactly this is done.
Or with 1.7, even better way would be to use JacksonFeatureJsonFilter, which finally gives full dynamic control for application. Annotation is needed for value types, to indicate logical filter id to use, but mapping from id to filter is fully dynamic (on per-call basis if necessary).