23
23
*/
24
24
package com .sun .jna ;
25
25
26
+ import java .lang .annotation .Documented ;
27
+ import java .lang .annotation .ElementType ;
28
+ import java .lang .annotation .Retention ;
29
+ import java .lang .annotation .RetentionPolicy ;
30
+ import java .lang .annotation .Target ;
26
31
import java .lang .reflect .Array ;
27
32
import java .lang .reflect .Constructor ;
28
33
import java .lang .reflect .Field ;
38
43
import java .util .HashSet ;
39
44
import java .util .Iterator ;
40
45
import java .util .LinkedHashMap ;
46
+ import java .util .LinkedList ;
41
47
import java .util .List ;
42
48
import java .util .Map ;
43
49
import java .util .Set ;
66
72
* public. If your structure is to have no fields of its own, it must be
67
73
* declared abstract.
68
74
* </p>
69
- * <p>You <em>must</em> define {@link #getFieldOrder} to return a List of
70
- * field names (Strings) indicating the proper order of the fields. When
71
- * dealing with multiple levels of subclasses of Structure, you must add to
72
- * the list provided by the superclass {@link #getFieldOrder}
73
- * the fields defined in the current class.
75
+ * <p>You <em>must</em> annotate the class with {@link FieldOrder} or implement
76
+ * {@link #getFieldOrder}, whichever you choose it must contain the field names
77
+ * (Strings) indicating the proper order of the fields. If you chose to implement
78
+ * {@link #getFieldOrder} notice that when dealing with multiple levels of
79
+ * subclasses of Structure, you must add to the list provided by the superclass
80
+ * {@link #getFieldOrder} the fields defined in the current class.
74
81
* </p>
75
82
* <p>In the past, most VMs would return them in a predictable order, but the JVM
76
83
* spec does not require it, so {@link #getFieldOrder} is now required to
@@ -865,20 +872,66 @@ protected void writeField(StructField structField) {
865
872
}
866
873
}
867
874
868
- /** Return this Structure's field names in their proper order. For
869
- * example,
875
+ /** Used to declare fields order as metadata instead of method.
876
+ * example:
870
877
* <pre><code>
871
- * protected List getFieldOrder() {
872
- * return Arrays.asList(new String[] { ... });
878
+ * // New
879
+ * {@literal @}FieldOrder({ "n", "s" })
880
+ * class Parent extends Structure {
881
+ * public int n;
882
+ * public String s;
883
+ * }
884
+ * {@literal @}FieldOrder({ "d", "c" })
885
+ * class Son extends Parent {
886
+ * public double d;
887
+ * public char c;
888
+ * }
889
+ * // Old
890
+ * class Parent extends Structure {
891
+ * public int n;
892
+ * public String s;
893
+ * protected List<String> getFieldOrder() {
894
+ * return Arrays.asList("n", "s");
895
+ * }
896
+ * }
897
+ * class Son extends Parent {
898
+ * public double d;
899
+ * public char c;
900
+ * protected List<String> getFieldOrder() {
901
+ * List<String> fields = new LinkedList<String>(super.getFieldOrder());
902
+ * fields.addAll(Arrays.asList("d", "c"));
903
+ * return fields;
904
+ * }
905
+ * }
906
+ * </code></pre>
907
+ */
908
+ @ Documented
909
+ @ Retention (RetentionPolicy .RUNTIME )
910
+ @ Target (ElementType .TYPE )
911
+ public @interface FieldOrder {
912
+ String [] value ();
913
+ }
914
+
915
+ /** Returns this Structure's field names in their proper order.<br>
916
+ *
917
+ * When defining a new {@link Structure} you shouldn't override this
918
+ * method, but use {@link FieldOrder} annotation to define your field
919
+ * order(this also works with inheritance)<br>
920
+ *
921
+ * If you want to do something non-standard you can override the method
922
+ * and define it as followed
923
+ * <pre><code>
924
+ * protected List<String> getFieldOrder() {
925
+ * return Arrays.asList(...);
873
926
* }
874
927
* </code></pre>
875
928
* <strong>IMPORTANT</strong>
876
929
* When deriving from an existing Structure subclass, ensure that
877
930
* you augment the list provided by the superclass, e.g.
878
931
* <pre><code>
879
- * protected List getFieldOrder() {
880
- * List fields = new ArrayList (super.getFieldOrder());
881
- * fields.addAll(Arrays.asList(new String[] { ... } ));
932
+ * protected List<String> getFieldOrder() {
933
+ * List<String> fields = new LinkedList<String> (super.getFieldOrder());
934
+ * fields.addAll(Arrays.asList(...));
882
935
* return fields;
883
936
* }
884
937
* </code></pre>
@@ -888,7 +941,19 @@ protected void writeField(StructField structField) {
888
941
* guaranteed to be predictable.
889
942
* @return ordered list of field names
890
943
*/
891
- protected abstract List <String > getFieldOrder ();
944
+ // TODO(idosu 28 Apr 2018): Maybe deprecate this method to let users know they should use @FieldOrder
945
+ protected List <String > getFieldOrder () {
946
+ List <String > fields = new LinkedList <String >();
947
+ for (Class <?> clazz = getClass (); clazz != Structure .class ; clazz = clazz .getSuperclass ()) {
948
+ FieldOrder order = clazz .getAnnotation (FieldOrder .class );
949
+ if (order != null ) {
950
+ fields .addAll (0 , Arrays .asList (order .value ()));
951
+ }
952
+ }
953
+
954
+ // fields.isEmpty() can be true because it is check somewhere else
955
+ return Collections .unmodifiableList (fields );
956
+ }
892
957
893
958
/** Sort the structure fields according to the given array of names.
894
959
* @param fields list of fields to be sorted
@@ -1855,6 +1920,7 @@ public String toString() {
1855
1920
* structure for use by libffi. The lifecycle of this structure is easier
1856
1921
* to manage on the Java side than in native code.
1857
1922
*/
1923
+ @ FieldOrder ({ "size" , "alignment" , "type" , "elements" })
1858
1924
static class FFIType extends Structure {
1859
1925
public static class size_t extends IntegerType {
1860
1926
private static final long serialVersionUID = 1L ;
@@ -1951,11 +2017,7 @@ private FFIType(Object array, Class<?> type) {
1951
2017
}
1952
2018
init (els );
1953
2019
}
1954
-
1955
- @ Override
1956
- protected List <String > getFieldOrder () {
1957
- return Arrays .asList (new String [] { "size" , "alignment" , "type" , "elements" });
1958
- }
2020
+
1959
2021
private void init (Pointer [] els ) {
1960
2022
elements = new Memory (Native .POINTER_SIZE * els .length );
1961
2023
elements .write (0 , els , 0 , els .length );
0 commit comments