2121
2222import com .aerospike .client .AerospikeException ;
2323import com .aerospike .client .Bin ;
24+ import com .aerospike .client .Key ;
2425import com .aerospike .client .Record ;
26+ import com .aerospike .client .Value ;
2527import com .aerospike .client .cdt .MapOrder ;
2628import com .aerospike .client .policy .BatchPolicy ;
2729import com .aerospike .client .policy .Policy ;
@@ -137,8 +139,8 @@ public ClassCacheEntry<T> construct() {
137139 this .overrideSettings (config );
138140 }
139141
140- this .loadFieldsFromClass (clazz , this . mapAll , config );
141- this .loadPropertiesFromClass (clazz , config );
142+ this .loadFieldsFromClass ();
143+ this .loadPropertiesFromClass ();
142144 this .superClazz = ClassCache .getInstance ().loadClass (this .clazz .getSuperclass (), this .mapper );
143145 this .binCount = this .values .size () + (superClazz != null ? superClazz .binCount : 0 );
144146 if (this .binCount == 0 ) {
@@ -538,7 +540,7 @@ private PropertyDefinition getOrCreateProperty(String name, Map<String, Property
538540 return thisProperty ;
539541 }
540542
541- private void loadPropertiesFromClass (@ NotNull Class <?> clazz , ClassConfig config ) {
543+ private void loadPropertiesFromClass () {
542544 Map <String , PropertyDefinition > properties = new HashMap <>();
543545 PropertyDefinition keyProperty = null ;
544546 KeyConfig keyConfig = config != null ? config .getKey () : null ;
@@ -617,10 +619,10 @@ private void loadPropertiesFromClass(@NotNull Class<?> clazz, ClassConfig config
617619 }
618620 }
619621
620- private void loadFieldsFromClass (Class <?> clazz , boolean mapAll , ClassConfig config ) {
622+ private void loadFieldsFromClass () {
621623 KeyConfig keyConfig = config != null ? config .getKey () : null ;
622624 String keyField = keyConfig == null ? null : keyConfig .getField ();
623- for (Field thisField : clazz .getDeclaredFields ()) {
625+ for (Field thisField : this . clazz .getDeclaredFields ()) {
624626 boolean isKey = false ;
625627 BinConfig thisBin = getBinFromField (thisField );
626628 if (thisField .isAnnotationPresent (AerospikeKey .class ) || (!StringUtils .isBlank (keyField ) && keyField .equals (thisField .getName ()))) {
@@ -643,7 +645,6 @@ private void loadFieldsFromClass(Class<?> clazz, boolean mapAll, ClassConfig con
643645
644646 if (this .mapAll || thisField .isAnnotationPresent (AerospikeBin .class ) || thisBin != null ) {
645647 // This field needs to be mapped
646- thisField .setAccessible (true );
647648 AerospikeBin bin = thisField .getAnnotation (AerospikeBin .class );
648649 String binName = bin == null ? null : ParserUtils .getInstance ().get (bin .name ());
649650 if (thisBin != null && !StringUtils .isBlank (thisBin .getDerivedName ())) {
@@ -652,25 +653,81 @@ private void loadFieldsFromClass(Class<?> clazz, boolean mapAll, ClassConfig con
652653 String name ;
653654 if (StringUtils .isBlank (binName )) {
654655 name = thisField .getName ();
655- }
656- else {
656+ } else {
657657 name = binName ;
658658 }
659659 if (isKey ) {
660660 this .keyName = name ;
661661 }
662-
662+
663663 if (this .values .get (name ) != null ) {
664664 throw new AerospikeException ("Class " + clazz .getName () + " cannot define the mapped name " + name + " more than once" );
665665 }
666- AnnotatedType annotatedType = new AnnotatedType (config , thisField );
667- TypeMapper typeMapper = TypeUtils .getMapper (thisField .getType (), annotatedType , this .mapper );
668- ValueType valueType = new ValueType .FieldValue (thisField , typeMapper , annotatedType );
669- values .put (name , valueType );
666+ if ((bin != null && bin .useAccessors ()) || (thisBin != null && thisBin .getUseAccessors () != null && thisBin .getUseAccessors ())) {
667+ validateAccessorsForField (name , thisField );
668+ } else {
669+ thisField .setAccessible (true );
670+ AnnotatedType annotatedType = new AnnotatedType (config , thisField );
671+ TypeMapper typeMapper = TypeUtils .getMapper (thisField .getType (), annotatedType , this .mapper );
672+ ValueType valueType = new ValueType .FieldValue (thisField , typeMapper , annotatedType );
673+ values .put (name , valueType );
674+ }
670675 }
671676 }
672677 }
673678
679+ private Method findMethodWithNameAndParams (String name , Class <?> ... params ) {
680+ try {
681+ Method method = this .clazz .getDeclaredMethod (name , params );
682+ // TODO: Should this ascend the inheritance hierarchy using getMethod on superclasses?
683+ return method ;
684+ } catch (NoSuchMethodException nsme ) {
685+ return null ;
686+ }
687+ }
688+
689+ private void validateAccessorsForField (String binName , Field thisField ) {
690+ String fieldName = thisField .getName ();
691+ String methodNameBase = fieldName .substring (0 , 1 ).toUpperCase () + fieldName .substring (1 );
692+ String getterName = "get" + methodNameBase ;
693+ String setterName = "set" + methodNameBase ;
694+
695+ Method getter = findMethodWithNameAndParams (getterName );
696+ if (getter == null ) {
697+ throw new AerospikeException (String .format (
698+ "Expected to find getter for field %s on class %s due to it being configured to useAccessors, but no method with the signature \" %s %s()\" was found" ,
699+ fieldName ,
700+ this .clazz .getSimpleName (),
701+ thisField .getType ().getSimpleName (),
702+ getterName ));
703+ }
704+
705+ Method setter = findMethodWithNameAndParams (setterName , thisField .getType ());
706+ if (setter == null ) {
707+ setter = findMethodWithNameAndParams (setterName , thisField .getType (), Key .class );
708+ }
709+ if (setter == null ) {
710+ setter = findMethodWithNameAndParams (setterName , thisField .getType (), Value .class );
711+ }
712+ if (setter == null ) {
713+ throw new AerospikeException (String .format (
714+ "Expected to find setter for field %s on class %s due to it being configured to useAccessors, but no method with the name \" %s\" was found" ,
715+ fieldName ,
716+ this .clazz .getSimpleName (),
717+ setterName ));
718+ }
719+
720+ AnnotatedType annotatedType = new AnnotatedType (config , thisField );
721+ TypeMapper typeMapper = TypeUtils .getMapper (thisField .getType (), annotatedType , this .mapper );
722+ PropertyDefinition property = new PropertyDefinition (binName , mapper );
723+ property .setGetter (getter );
724+ property .setSetter (setter );
725+ property .validate (clazz .getName (), config , false );
726+
727+ ValueType value = new ValueType .MethodValue (property , typeMapper , annotatedType );
728+ values .put (binName , value );
729+ }
730+
674731 public Object translateKeyToAerospikeKey (Object key ) {
675732 return this .key .getTypeMapper ().toAerospikeFormat (key );
676733 }
0 commit comments