锘??xml version="1.0" encoding="utf-8" standalone="yes"?>
鏈漢涔熸槸鍒氬涔燬eam 3錛岀敱浜庤祫鏂欏お灝戯紝鎵浠ュ氨緲昏瘧璧峰畼鏂瑰嚭鐨勫弬鑰冦傜敱浜庤嫳鏂囧姛搴曞お宸紝姣忔鐪嬪緱閮藉緢鍚冨姏錛屽氨緲昏瘧鍑烘潵澶у涓璧峰涔犮傝繕璇鋒寚姝i敊璇?/font>
1. Annotated Type Builder 娉ㄩ噴綾誨瀷鐢熸垚鍣?/font>
2. Annotation Instance Provider 娉ㄩ噴瀹炰緥鎻愪緵鍣?/font>
3. Annotation Inspector 娉ㄨВ媯鏌ュ櫒
4. Synthetic Qualifiers 緇勫悎淇グ絎?/font>
5. Reflection Utilities 鍙嶅皠鍏叡綾?/font>
Seam Solder provides a number of utilility classes that make working with annotations and AnnotatedTypes easier. This chapter walks you through each utility, and gives you some ideas about how to use it. For more detail, take a look at the JavaDoc on each class.
Seam Solder鎻愪緵涓浜涘叕鍏辯被璁╂敞瑙e拰娉ㄨВ綾誨瀷鏇村姞瀹規槗宸ヤ綔銆傛湰绔犲皢閫氳繃姣忎釜宸ュ叿綾誨紩瀵兼偍錛屽茍涓烘偍鎻愪緵鏈夊叧濡備綍浣跨敤瀹冪殑涓浜涙兂娉曘傚浜庢洿澶氱殑緇嗚妭錛岀湅鐪嬫瘡涓被鐨凧avaDoc銆?/font>
Seam Solder provides an AnnotatedType implementation that should be suitable for the needs of most portable extensions. The AnnotatedType is created from AnnotatedTypeBuilder, typically in an extension's observer method, as follows:
Seam Solder 鎻愪緵涓涓狝nnotatedType鎺ュ彛鏉ュ疄鐜板ぇ澶氭暟鐨勯渶姹傛墿灞曘侫nnotatedType 鏄氳繃 AnnotatedTypeBuilder鐨勪竴涓柟娉曡繑鍥炲緱鍒幫紝濡備笅錛?/font>
AnnotatedTypeBuilder builder = new AnnotatedTypeBuilder().readFromType(type, true) /* readFromType can read from an AnnotatedType or a class */ .addToClass(ModelLiteral.INSTANCE); /* add the @Model annotation */
Here we create a new builder, and initialize it using an existing AnnotatedType. We can then add or remove annotations from the class, and its members. When we have finished modifying the type, we call create() to spit out a new, immutable, AnnotatedType.
榪欓噷鎴戜滑鏈変竴涓柊鐨勫璞″疄渚嬶紝騫跺垵濮嬪寲浜嗗畠鐜版湁鐨?AnnotatedType銆傜劧鍚庢垜浠彲浠ヤ負榪欎釜綾諱互鍙婂畠鐨勬垚鍛樻坊鍔犳垨鑰呯Щ闄ゆ敞瑙c傚綋 鎴戜滑瀹屾垚淇敼鍚庯紝鎴戜滑鍙互璋冪敤create() 鏉ヨ幏寰椾竴涓柊鐨凙nnotatedType瀵硅薄銆?/font>
AnnotatedType redefinedType = builder.create();
One place this is immensely useful is for replacing the AnnotatedType in an extension that observes the ProcessAnnotatedType event:
瀵筆rocessAnnotatedType榪涜浜嬩歡鐩戝惉瀵逛慨鏀笰nnotatedType鏄竴涓潪甯告湁鐢ㄧ殑鎵╁睍錛?/font>
public <X> void processAnnotatedType(@Observes ProcessAnnotatedType<X> evt) { AnnotatedTypeBuilder builder = new AnnotatedTypeBuilder() .readFromType(evt.getAnnotatedType(), true) .addToClass(ModelLiteral.INSTANCE); evt.setAnnotatedType(builder.create()); }
This type is now effectively annotated with @Model, even if the annotation is not present on the class definition in the Java source file.
鐜板湪榪欓噷鐨勬敞瑙g被鍨嬫槸@Model錛屽嵆浣垮湪Java婧愭枃浠朵腑瀵硅繖涓被涓嶆槸榪欐牱瀹氫箟鐨勩?/font>
AnnotatedTypeBuilder also allows you to specify a "redefinition", which can be applied to the type, a type of member, or all members. The redefiner will receive a callback for any annotations present which match the annotation type for which the redefinition is applied.
AnnotatedTypeBuilder 榪樺厑璁鎬綘鑷繁瀹氫箟涓涓?#8220;閲嶅畾涔?#8221;錛屽畠鍙互鐢ㄤ簬綾誨瀷錛岀被鍨嬬殑鎴愬憳鎴栨墍鏈夋垚鍛樸傞噸鏂板畾涔夌殑綾誨瀷鍙互鎺ュ彈浠諱綍浣跨敤閲嶆柊瀹氫箟鐨勬敞瑙g殑鍥炶皟銆?/font>
For example, to remove the qualifier @Unique from the type and any of its members, use this:
渚嬪錛屽榪欎釜綾誨瀷鍘繪帀@Unique淇グ絎︼紝閭d箞瀹冪殑鎵鏈夋垚鍛橀兘鍥炴敼鍙橈細
AnnotatedTypeBuilder builder = new AnnotatedTypeBuilder().readFromType(type, true).redefine(Unique.class, new AnnotationRedefiner<Unique>() { public void redefine(RedefinitionContext<A> ctx) { ctx.getAnnotationBuilder().remove(Unique.class); } }); AnnotatedType redefinedType = builder.create();
No doubt, this is a key blade in Solder's army knife arsenal of tools. You can quite effectively change the picture of the type metadata CDI discovers when it scans and processes the classpath of a bean archive.
姣棤鐤戦棶錛岃繖鏄墦寮Solder宸ュ叿鍐涘簱鐨勯挜鍖欍傚綋CDI鎵弿鍣ㄦ煡鎵懼茍澶勭悊classpath涓媌ean鐩綍鐨勬椂鍊欙紝浣犲彲浠ラ潪甯告湁鏁堝湴鏀瑰彉綾誨瀷鐨勫厓鏁版嵁銆?/font>
Sometimes you may need an annotation instance for an annotation whose type is not known at development time. Seam Solder provides a AnnotationInstanceProvider class that can create an AnnotationLiteral instance for any annotation at runtime. Annotation attributes are passed in via aMap<String,Object>. For example given the follow annotation:
鍦ㄥ紑鍙戞椂錛屾湁鏃朵綘鍙兘闇瑕佽幏寰椾竴涓笉鐭ラ亾鍏剁被鍨嬫敞瑙g殑娉ㄨВ瀹炰緥銆係eam Solder鎻愪緵浜嗕竴涓狝nnotationInstanceProvider綾伙紝瀹冨彲浠ュ湪榪愯鏃跺垱寤轟竴涓換浣曟敞閲夾nnotationLiteral鐨勫疄渚嬨傛敞閲婂睘鎬ф槸閫氳繃浼犻扢ap<String,Object> 銆備緥濡傦紝緇欏畾浠ヤ笅娉ㄨВ錛?/font>
@Retention(RetentionPolicy.RUNTIME) public @interface MultipleMembers { int intMember(); long longMember(); short shortMember(); float floatMember(); double doubleMember(); byte byteMember(); char charMember(); boolean booleanMember(); int[] intArrayMember(); }
We can create an annotation instance as follows:
鎴戜滑鍙互鍒涘緩浠ヤ笅娉ㄨВ瀹炰緥錛?/font>
/* Create a new provider */ AnnotationInstanceProvider provider = new AnnotationInstanceProvider(); /* Set the value for each of attributes */ Map<String, Object> values = new HashMap<String, Object>(); values.put("intMember", 1); values.put("longMember", 1); values.put("shortMember", 1); values.put("floatMember", 0); values.put("doubleMember", 0); values.put("byteMember", ((byte) 1)); values.put("charMember", 'c'); values.put("booleanMember", true); values.put("intArrayMember", new int[] { 0, 1 }); /* Generate the instance */ MultipleMembers an = provider.get(MultipleMembers.class, values);
The Annotation Inspector allows you to easily discover annotations which are meta-annotated. For example:
娉ㄨВ媯鏌ュ櫒鍙互杞繪澗鍦板彂鐜伴偅浜涘厓娉ㄨВ銆備緥濡傦細
/* Discover all annotations on type which are meta-annotated @Constraint */ Set<Annotation> constraints = AnnotationInspector.getAnnotations(type,Constraint.class,beanManager); /* Load the annotation instance for @FacesValidator the annotation may declared on the type, */ /* or, if the type has any stereotypes, on the stereotypes */ FacesValidator validator = AnnotationInspector.getAnnotation( type, FacesValidator.class, true, beanManager);
The utility methods work correctly on Stereotypes as well. Let's say you're working with a bean that was decorated @Model, running the following example will still show you the underlying @Named.
榪欎簺瀹炵敤鏂規硶涔熻兘鐢ㄤ簬Stereotypes錛堝鍚堟敞瑙o級銆傚亣濡傛垜浠湁涓涓猙ean琚祴浜堜簡@Model娉ㄨВ錛岃繍琛屼笅闈㈢殑渚嬪瓙浣犲氨鍙互鎴栬呴殣钘忕殑娉ㄨВ@Named
// assuming you have a class.. @Model public class User { … } // Assume type represents the User class assert AnnotationInspector.isAnnotationPresent(type, Named.class, beanManager); // Retrieves the underlying @Named instance on the stereotype Named name = AnnotationInspector.getAnnotation(type, Named.class, true, beanManager);
The search algorithm will first check to see if the annotation is present directly on the annotated element first, then searches within the stereotype annotations on the element. If you only want to search for Annotations on Stereotypes, then you can use either of the methods AnnotationInspector.getAnnotationFromStereotype.
鎼滅儲鏂規硶浼氶鍏堟煡鎵捐繖涓洿鎺ユ坊鍔犵殑娉ㄨВ鍏冪礌錛岀劧鍚庝細瀵瑰鍚堢被鍨嬭繘琛屾煡鎵俱傚鏋滀綘瑕佺洿鎺ュ閭d簺澶嶅悎娉ㄨВ榪涜鏌ユ壘錛屼綘鍙互璋冪敤鍙﹀涓涓柟娉曪紝AnnotationInspector.getAnnotationFromStereotype.
There is an overloaded form of isAnnotationPresent and getAnnotation to control whether it will search on Stereotypes or not. For both of these methods, a search is performed first directly on the element before searching in stereotypes.
榪欐槸瀵?isAnnotationPresent 鍜?getAnnotation 涓や釜鏂規硶鐨勯噸鏂拌皟鐢ㄥ垽鏂畠鏄笉鏄竴涓鍚堢被鍨嬬殑娉ㄨВ銆備互涓婄殑鏃犺鍝釜鏂規硶閮藉厛瀵圭洿鎺ョ被鍨嬫敞瑙h繘琛屾煡鎵俱?/font>
When developing an extension to CDI, it can be useful to detect certain injection points, or bean definitions and based on annotations or other metadata, add qualifiers to further disambiguate the injection point or bean definition for the CDI bean resolver. Solder's synthetic qualifers can be used to easily generate and track such qualifers.
褰撳CDI榪涜鎵╁睍鏃訛紝瀹冨彲浠ヤ負CDI bean 鍒嗘瀽鍣ㄦ湁鏁堝湴鍙戠幇宸叉湁鐨勬敞鍏ョ偣鎴朾ean鐨勫畾涔夎繕鏈夊熀鏈殑娉ㄨВ鎴栧叾浠栧厓鏁版嵁錛屾坊鍔犱慨楗扮鏉ヨ繘涓姝ユ秷闄よ繖浜涙敞鍏ョ偣鎴朾ean鐨勫畾涔夈傦紙緲昏瘧鐨勫緢涓嶉氾級Solder鐨勭粍鍚堜慨楗扮鍙互鐢ㄦ潵鏂逛究鍦扮敓浜ц窡韙繖浜涗慨楗扮銆?/font>
In this example, we will create a synthetic qualifier provider, and use it to create a qualifier. The provider will track the qualifier, and if a qualifier is requested again for the same original annotation, the same instance will be returned.
鍦ㄨ繖涓緥瀛愪腑錛屾垜浠皢鍒涘緩涓涓粍鍚堜慨楗扮鎻愪緵鍣紝騫剁敤瀹冩潵鍒涘緩涓涓慨楗扮銆傝繖涓彁渚涘櫒浼氳窡韙繖涓猶ualifier錛屽鏋滆繖涓猶ualifier琚啀嬈¤皟鐢紝瀹冧細榪斿洖璺熶笂嬈$浉鍚岀殑瀹炰緥銆?/font>
/* Create a provider, giving it a unique namespace */ Synthetic.Provider provider = new Synthetic.Provider("com.acme"); /* Get the a synthetic qualifier for the original annotation instance */ Synthetic synthetic = provider.get(originalAnnotation); /* Later calls with the same original annotation instance will return the same instance */ /* Alternatively, we can "get and forget" */ Synthetic synthetic2 = provider.get();
Seam Solder comes with a number miscellaneous reflection utilities; these extend JDK reflection, and some also work on CDI's Annotated metadata. See the javadoc on Reflections for more.
Seam Solder 鎻愪緵浜嗕竴浜涘鏂歸潰鐨勫弽灝勫伐鍏風被錛涜繖浜涙槸瀵笿DK鍙嶅皠鏈哄埗鐨勬墿灞曪紝涔熺敤浜庡CDI鍏冩暟鎹殑澶勭悊銆傛洿澶氬緱璇風湅鏈夊叧鏀懼皠鏈哄埗鐨刯ava鏂囨。銆?/font>
Solder also includes a simple utility, PrimitiveTypes for converting between primitive and their respective wrapper types, which may be useful when performing data type conversion. Sadly, this is functionality which is missing from the JDK.
Solder 涔熸湁涓涓畝鍗曠殑宸ュ叿綾伙紝鍦ㄥ鍩烘湰鏁版嵁綾誨瀷杞寲鐨勬椂鍊欙紝PrimitiveTypes鍙互寰堝ソ鍦板畬鎴愬鏁版嵁鍦ㄥ叾鍘熷綾誨瀷璺熷寘瑁呯被鍨嬩箣闂磋漿鍖栥傚彲鎮茬殑鏄紝榪欐槸JDK涓己灝戠殑鍔熻兘銆?/font>
InjectableMethod allows an AnnotatedMethod to be injected with parameter values obtained by following the CDI type safe resolution rules, as well as allowing the default parameter values to be overridden.
InjectableMethod鍏佽AnnotatedMethod琚綔涓轟竴涓鍚圕DI綾誨瀷瀹夊叏瑙e喅瑙勫垯鐨勫弬鏁板兼敞鍏ワ紝涔熷厑璁擱粯璁ょ殑鍙傛暟鍊艱瑕嗙洊閲嶅啓銆?/font>