001/*
002 *  Copyright 2013 Christopher Pheby
003 *
004 *  Licensed under the Apache License, Version 2.0 (the "License");
005 *  you may not use this file except in compliance with the License.
006 *  You may obtain a copy of the License at
007 *
008 *      http://www.apache.org/licenses/LICENSE-2.0
009 *
010 *  Unless required by applicable law or agreed to in writing, software
011 *  distributed under the License is distributed on an "AS IS" BASIS,
012 *  WITHOUT WARRANTIES OR CONDITIONS OObject ANY KIND, either express or implied.
013 *  See the License for the specific language governing permissions and
014 *  limitations under the License.
015 */
016package org.jadira.reflection.access.portable;
017
018import java.lang.reflect.Field;
019
020import org.jadira.reflection.access.api.FieldAccess;
021
022/**
023 * FieldAccess implementation which should be portable across most JVMs. 
024 * @param <C> The Class to be accessed
025 */
026public class PortableFieldAccess<C> implements FieldAccess<C> {
027
028        private Field field;
029        private Class<C> declaringClass;        
030        private Class<?> type;  
031
032        @SuppressWarnings("unchecked")
033        private PortableFieldAccess(Field f) {
034                this.field = f;
035                if (!field.isAccessible()) {
036                        field.setAccessible(true);
037                }
038                this.declaringClass = (Class<C>) f.getDeclaringClass();
039                this.type = (Class<?>) f.getType();
040        }
041        
042        @Override
043        public Class<C> declaringClass() {
044                return declaringClass;
045        }
046
047        @Override
048        public Class<?> fieldClass() {
049                return type;
050        }
051
052        @Override
053        public Field field() {
054                return field;
055        }
056        
057        @Override
058        public Object getValue(C parent) {
059                try {
060                        return (Object) field.get(parent);
061                } catch (IllegalArgumentException e) {
062            throw new IllegalStateException("Problem target object {" + field.getName() + "} of object {"
063                    + System.identityHashCode(parent) + "}: " + e.getMessage(), e);
064        } catch (IllegalAccessException e) {
065            throw new IllegalStateException("Problem accessing {" + field.getName() + "} of object {"
066                    + System.identityHashCode(parent) + "}: " + e.getMessage(), e);
067        }
068        }
069
070        @Override
071        public boolean getBooleanValue(C parent) {
072                throw new UnsupportedOperationException("Not supported for this field type");
073        }
074        
075        @Override
076        public byte getByteValue(C parent) {
077                throw new UnsupportedOperationException("Not supported for this field type");
078        }
079        
080        @Override
081        public char getCharValue(C parent) {
082                throw new UnsupportedOperationException("Not supported for this field type");
083        }
084        
085        @Override
086        public short getShortValue(C parent) {
087                throw new UnsupportedOperationException("Not supported for this field type");
088        }
089        
090        @Override
091        public int getIntValue(C parent) {
092                throw new UnsupportedOperationException("Not supported for this field type");
093        }
094        
095        @Override
096        public long getLongValue(C parent) {
097                throw new UnsupportedOperationException("Not supported for this field type");
098        }
099        
100        @Override
101        public float getFloatValue(C parent) {
102                throw new UnsupportedOperationException("Not supported for this field type");
103        }
104        
105        @Override
106        public double getDoubleValue(C parent) {
107                throw new UnsupportedOperationException("Not supported for this field type");
108        }
109        
110        @Override
111        public void putValue(C parent, Object newFieldValue) {
112        try {
113            field.set(parent, newFieldValue);
114        } catch (IllegalArgumentException e) {
115            throw new IllegalStateException("Problem argument for field {" + field.getName() + "} of object {"
116                    + System.identityHashCode(newFieldValue) + "}: " + e.getMessage(), e);
117        } catch (IllegalAccessException e) {
118            throw new IllegalStateException("Problem accessing for field {" + field.getName() + "} of object {"
119                    + System.identityHashCode(newFieldValue) + "}: " + e.getMessage(), e);
120        }
121        }
122        
123        @Override
124        public void putBooleanValue(C parent, boolean newFieldValue) {
125                throw new UnsupportedOperationException("Not supported for this field type");
126        }
127        
128        @Override
129        public void putByteValue(C parent, byte newFieldValue) {
130                throw new UnsupportedOperationException("Not supported for this field type");
131        }
132        
133        @Override
134        public void putCharValue(C parent, char newFieldValue) {
135                throw new UnsupportedOperationException("Not supported for this field type");
136        }
137        
138        @Override
139        public void putShortValue(C parent, short newFieldValue) {
140                throw new UnsupportedOperationException("Not supported for this field type");
141        }
142        
143        @Override
144        public void putIntValue(C parent, int newFieldValue) {
145                throw new UnsupportedOperationException("Not supported for this field type");
146        }
147        
148        @Override
149        public void putLongValue(C parent, long newFieldValue) {
150                throw new UnsupportedOperationException("Not supported for this field type");
151        }
152        
153        @Override
154        public void putFloatValue(C parent, float newFieldValue) {
155                throw new UnsupportedOperationException("Not supported for this field type");
156        }
157        
158        @Override
159        public void putDoubleValue(C parent, double newFieldValue) {
160                throw new UnsupportedOperationException("Not supported for this field type");
161        }
162        
163        /**
164         * Get a new instance that can access the given Field
165         * @param f Field to be accessed
166         * @param <C> The type of class being accessed
167         * @return New PortableFieldAccess instance
168         */
169        public static <C> PortableFieldAccess<C> get(Field f) {
170                
171                Class<?> type = (Class<?>) f.getType();
172                
173                if (type.isPrimitive()) {
174                        if (java.lang.Boolean.TYPE == type) {
175                                return (PortableFieldAccess<C>) new PortableBooleanFieldAccess<C>(f);
176                        } else if (java.lang.Byte.TYPE == type) {
177                                return (PortableFieldAccess<C>) new PortableByteFieldAccess<C>(f);
178                        } else if (java.lang.Character.TYPE == type) {
179                                return (PortableFieldAccess<C>) new PortableCharFieldAccess<C>(f);
180                        } else if (java.lang.Short.TYPE == type) {
181                                return (PortableFieldAccess<C>) new PortableShortFieldAccess<C>(f);
182                        } else if (java.lang.Integer.TYPE == type) {
183                                return (PortableFieldAccess<C>) new PortableIntFieldAccess<C>(f);
184                        } else if (java.lang.Long.TYPE == type) {
185                                return (PortableFieldAccess<C>) new PortableLongFieldAccess<C>(f);
186                        } else if (java.lang.Float.TYPE == type) {
187                                return (PortableFieldAccess<C>) new PortableFloatFieldAccess<C>(f);
188                        } else if (java.lang.Double.TYPE == type) {
189                                return (PortableFieldAccess<C>) new PortableDoubleFieldAccess<C>(f);
190                        }
191                }
192                return new PortableFieldAccess<C>(f);
193        }
194        
195        /**
196         * PortableFieldAccess implementation suitable for accessing boolean fields
197         * @param <C> The Class containing the Field to be accessed
198         */
199        public static class PortableBooleanFieldAccess<C> extends PortableFieldAccess<C> {
200
201                /**
202                 * Construct a new instance for the given Field
203                 * @param f The Field to be accessed
204                 */
205                public PortableBooleanFieldAccess(Field f) {
206                        super(f);
207                }
208
209                @Override
210                public boolean getBooleanValue(C parent) {
211                        try {
212                                return super.field.getBoolean(parent);
213                        } catch (IllegalArgumentException e) {
214                    throw new IllegalStateException("Problem target object {" + super.field.getName() + "} of object {"
215                            + System.identityHashCode(parent) + "}: " + e.getMessage(), e);
216                } catch (IllegalAccessException e) {
217                    throw new IllegalStateException("Problem accessing {" + super.field.getName() + "} of object {"
218                            + System.identityHashCode(parent) + "}: " + e.getMessage(), e);
219                }
220                }
221                
222                @Override
223                public void putBooleanValue(C parent, boolean newFieldValue) {
224                try {
225                    super.field.setBoolean(parent, newFieldValue);
226                } catch (IllegalArgumentException e) {
227                    throw new IllegalStateException("Problem argument for field {" + super.field.getName() + "} of object {"
228                            + System.identityHashCode(newFieldValue) + "}: " + e.getMessage(), e);
229                } catch (IllegalAccessException e) {
230                    throw new IllegalStateException("Problem accessing for field {" + super.field.getName() + "} of object {"
231                            + System.identityHashCode(newFieldValue) + "}: " + e.getMessage(), e);
232                }
233                }
234        }
235
236        /**
237         * PortableFieldAccess implementation suitable for accessing byte fields
238         * @param <C> The Class containing the Field to be accessed
239         */
240        public static class PortableByteFieldAccess<C> extends PortableFieldAccess<C> {
241
242                /**
243                 * Construct a new instance for the given Field
244                 * @param f The Field to be accessed
245                 */
246                public PortableByteFieldAccess(Field f) {
247                        super(f);
248                }
249
250                @Override
251                public byte getByteValue(C parent) {
252                        try {
253                                return super.field.getByte(parent);
254                        } catch (IllegalArgumentException e) {
255                    throw new IllegalStateException("Problem target object {" + super.field.getName() + "} of object {"
256                            + System.identityHashCode(parent) + "}: " + e.getMessage(), e);
257                } catch (IllegalAccessException e) {
258                    throw new IllegalStateException("Problem accessing {" + super.field.getName() + "} of object {"
259                            + System.identityHashCode(parent) + "}: " + e.getMessage(), e);
260                }
261                }
262                
263                @Override
264                public void putByteValue(C parent, byte newFieldValue) {
265                try {
266                    super.field.setByte(parent, newFieldValue);
267                } catch (IllegalArgumentException e) {
268                    throw new IllegalStateException("Problem argument for field {" + super.field.getName() + "} of object {"
269                            + System.identityHashCode(newFieldValue) + "}: " + e.getMessage(), e);
270                } catch (IllegalAccessException e) {
271                    throw new IllegalStateException("Problem accessing for field {" + super.field.getName() + "} of object {"
272                            + System.identityHashCode(newFieldValue) + "}: " + e.getMessage(), e);
273                }
274                }
275        }
276        
277        /**
278         * PortableFieldAccess implementation suitable for accessing char fields
279         * @param <C> The Class containing the Field to be accessed
280         */
281        public static class PortableCharFieldAccess<C> extends PortableFieldAccess<C> {
282
283                /**
284                 * Construct a new instance for the given Field
285                 * @param f The Field to be accessed
286                 */
287                public PortableCharFieldAccess(Field f) {
288                        super(f);
289                }
290
291                @Override
292                public char getCharValue(C parent) {
293                        try {
294                                return super.field.getChar(parent);
295                        } catch (IllegalArgumentException e) {
296                    throw new IllegalStateException("Problem target object {" + super.field.getName() + "} of object {"
297                            + System.identityHashCode(parent) + "}: " + e.getMessage(), e);
298                } catch (IllegalAccessException e) {
299                    throw new IllegalStateException("Problem accessing {" + super.field.getName() + "} of object {"
300                            + System.identityHashCode(parent) + "}: " + e.getMessage(), e);
301                }
302
303                }
304                
305                @Override
306                public void putCharValue(C parent, char newFieldValue) {
307                try {
308                    super.field.setChar(parent, newFieldValue);
309                } catch (IllegalArgumentException e) {
310                    throw new IllegalStateException("Problem argument for field {" + super.field.getName() + "} of object {"
311                            + System.identityHashCode(newFieldValue) + "}: " + e.getMessage(), e);
312                } catch (IllegalAccessException e) {
313                    throw new IllegalStateException("Problem accessing for field {" + super.field.getName() + "} of object {"
314                            + System.identityHashCode(newFieldValue) + "}: " + e.getMessage(), e);
315                }
316                }
317        }
318        
319        /**
320         * PortableFieldAccess implementation suitable for accessing short fields
321         * @param <C> The Class containing the Field to be accessed
322         */
323        public static class PortableShortFieldAccess<C> extends PortableFieldAccess<C> {
324
325                /**
326                 * Construct a new instance for the given Field
327                 * @param f The Field to be accessed
328                 */
329                public PortableShortFieldAccess(Field f) {
330                        super(f);
331                }
332
333                @Override
334                public short getShortValue(C parent) {
335                        try {
336                                return super.field.getShort(parent);
337                        } catch (IllegalArgumentException e) {
338                    throw new IllegalStateException("Problem target object {" + super.field.getName() + "} of object {"
339                            + System.identityHashCode(parent) + "}: " + e.getMessage(), e);
340                } catch (IllegalAccessException e) {
341                    throw new IllegalStateException("Problem accessing {" + super.field.getName() + "} of object {"
342                            + System.identityHashCode(parent) + "}: " + e.getMessage(), e);
343                }
344
345                }
346                
347                @Override
348                public void putShortValue(C parent, short newFieldValue) {
349                try {
350                    super.field.setShort(parent, newFieldValue);
351                } catch (IllegalArgumentException e) {
352                    throw new IllegalStateException("Problem argument for field {" + super.field.getName() + "} of object {"
353                            + System.identityHashCode(newFieldValue) + "}: " + e.getMessage(), e);
354                } catch (IllegalAccessException e) {
355                    throw new IllegalStateException("Problem accessing for field {" + super.field.getName() + "} of object {"
356                            + System.identityHashCode(newFieldValue) + "}: " + e.getMessage(), e);
357                }
358                }
359        }
360        
361        /**
362         * PortableFieldAccess implementation suitable for accessing int fields
363         * @param <C> The Class containing the Field to be accessed
364         */
365        public static class PortableIntFieldAccess<C> extends PortableFieldAccess<C> {
366
367                /**
368                 * Construct a new instance for the given Field
369                 * @param f The Field to be accessed
370                 */
371                public PortableIntFieldAccess(Field f) {
372                        super(f);
373                }
374
375                @Override
376                public int getIntValue(C parent) {
377                        try {
378                                return super.field.getInt(parent);
379                        } catch (IllegalArgumentException e) {
380                    throw new IllegalStateException("Problem target object {" + super.field.getName() + "} of object {"
381                            + System.identityHashCode(parent) + "}: " + e.getMessage(), e);
382                } catch (IllegalAccessException e) {
383                    throw new IllegalStateException("Problem accessing {" + super.field.getName() + "} of object {"
384                            + System.identityHashCode(parent) + "}: " + e.getMessage(), e);
385                }
386
387                }
388                
389                @Override
390                public void putIntValue(C parent, int newFieldValue) {
391                try {
392                    super.field.setInt(parent, newFieldValue);
393                } catch (IllegalArgumentException e) {
394                    throw new IllegalStateException("Problem argument for field {" + super.field.getName() + "} of object {"
395                            + System.identityHashCode(newFieldValue) + "}: " + e.getMessage(), e);
396                } catch (IllegalAccessException e) {
397                    throw new IllegalStateException("Problem accessing for field {" + super.field.getName() + "} of object {"
398                            + System.identityHashCode(newFieldValue) + "}: " + e.getMessage(), e);
399                }
400                }
401        }
402        
403        /**
404         * PortableFieldAccess implementation suitable for accessing long fields
405         * @param <C> The Class containing the Field to be accessed
406         */
407        public static class PortableLongFieldAccess<C> extends PortableFieldAccess<C> {
408
409                /**
410                 * Construct a new instance for the given Field
411                 * @param f The Field to be accessed
412                 */
413                public PortableLongFieldAccess(Field f) {
414                        super(f);
415                }
416
417                @Override
418                public long getLongValue(C parent) {
419                        try {
420                                return super.field.getLong(parent);
421                        } catch (IllegalArgumentException e) {
422                    throw new IllegalStateException("Problem target object {" + super.field.getName() + "} of object {"
423                            + System.identityHashCode(parent) + "}: " + e.getMessage(), e);
424                } catch (IllegalAccessException e) {
425                    throw new IllegalStateException("Problem accessing {" + super.field.getName() + "} of object {"
426                            + System.identityHashCode(parent) + "}: " + e.getMessage(), e);
427                }
428
429                }
430                
431                @Override
432                public void putLongValue(C parent, long newFieldValue) {
433                try {
434                    super.field.setLong(parent, newFieldValue);
435                } catch (IllegalArgumentException e) {
436                    throw new IllegalStateException("Problem argument for field {" + super.field.getName() + "} of object {"
437                            + System.identityHashCode(newFieldValue) + "}: " + e.getMessage(), e);
438                } catch (IllegalAccessException e) {
439                    throw new IllegalStateException("Problem accessing for field {" + super.field.getName() + "} of object {"
440                            + System.identityHashCode(newFieldValue) + "}: " + e.getMessage(), e);
441                }
442                }
443        }
444        
445        /**
446         * PortableFieldAccess implementation suitable for accessing float fields
447         * @param <C> The Class containing the Field to be accessed
448         */
449        public static class PortableFloatFieldAccess<C> extends PortableFieldAccess<C> {
450
451                /**
452                 * Construct a new instance for the given Field
453                 * @param f The Field to be accessed
454                 */
455                public PortableFloatFieldAccess(Field f) {
456                        super(f);
457                }
458
459                @Override
460                public float getFloatValue(C parent) {
461                        try {
462                                return super.field.getFloat(parent);
463                        } catch (IllegalArgumentException e) {
464                    throw new IllegalStateException("Problem target object {" + super.field.getName() + "} of object {"
465                            + System.identityHashCode(parent) + "}: " + e.getMessage(), e);
466                } catch (IllegalAccessException e) {
467                    throw new IllegalStateException("Problem accessing {" + super.field.getName() + "} of object {"
468                            + System.identityHashCode(parent) + "}: " + e.getMessage(), e);
469                }
470
471                }
472                
473                @Override
474                public void putFloatValue(C parent, float newFieldValue) {
475                try {
476                    super.field.setFloat(parent, newFieldValue);
477                } catch (IllegalArgumentException e) {
478                    throw new IllegalStateException("Problem argument for field {" + super.field.getName() + "} of object {"
479                            + System.identityHashCode(newFieldValue) + "}: " + e.getMessage(), e);
480                } catch (IllegalAccessException e) {
481                    throw new IllegalStateException("Problem accessing for field {" + super.field.getName() + "} of object {"
482                            + System.identityHashCode(newFieldValue) + "}: " + e.getMessage(), e);
483                }
484                }
485        }
486        
487        /**
488         * PortableFieldAccess implementation suitable for accessing double fields
489         * @param <C> The Class containing the Field to be accessed
490         */
491        public static class PortableDoubleFieldAccess<C> extends PortableFieldAccess<C> {
492
493                /**
494                 * Construct a new instance for the given Field
495                 * @param f The Field to be accessed
496                 */
497                public PortableDoubleFieldAccess(Field f) {
498                        super(f);
499                }
500
501                @Override
502                public double getDoubleValue(C parent) {
503                        try {
504                                return super.field.getDouble(parent);
505                        } catch (IllegalArgumentException e) {
506                    throw new IllegalStateException("Problem target object {" + super.field.getName() + "} of object {"
507                            + System.identityHashCode(parent) + "}: " + e.getMessage(), e);
508                } catch (IllegalAccessException e) {
509                    throw new IllegalStateException("Problem accessing {" + super.field.getName() + "} of object {"
510                            + System.identityHashCode(parent) + "}: " + e.getMessage(), e);
511                }
512
513                }
514                
515                @Override
516                public void putDoubleValue(C parent, double newFieldValue) {
517                try {
518                    super.field.setDouble(parent, newFieldValue);
519                } catch (IllegalArgumentException e) {
520                    throw new IllegalStateException("Problem argument for field {" + super.field.getName() + "} of object {"
521                            + System.identityHashCode(newFieldValue) + "}: " + e.getMessage(), e);
522                } catch (IllegalAccessException e) {
523                    throw new IllegalStateException("Problem accessing for field {" + super.field.getName() + "} of object {"
524                            + System.identityHashCode(newFieldValue) + "}: " + e.getMessage(), e);
525                }
526                }
527        }
528}