Thursday, April 17, 2014

Trading: Call Options - introduction

Investment oportunity


Imagine that you would meet somebody who is from the future.

And that somebody would tell you that each gold bar which
now costs 100$
will cost 115$ in a years time.

And imagine that for some reason you would believe him (as for example he looks exactly like you just 10 years older).

Now stop for a moment and think: What would you do regarding this gold situation?

Possible solution


It seems that a wise choice would be to invest all your money into gold and then sell it in a year.

You have 5,000$ in savings and the bank is willing to lend you maximum amount of 250,000$ with a generous interest rate of 5% per year.

So, let's do some calculations.

How much money do we actually have? This is a simple formula:
   our savings + borrowed money = 5,000 + 250,000 = 255,000 $

So, now the question is how many gold bars can we buy for this amount. To get this value we just divide our total amount by today's price of one gold bar:
   amount we have / today's price of gold bar = 255,000 / 100 = 2,550 gold bars

2,550 gold bars seems like a quite nice amount. But it would be good to actually know how much money we'll get for it in a year. To find it out just use this formula:
   amount of gold bars * price of gold bar in a year = 2,550 * 115 = 293,250 $
 
It seems that we have earned something. But how much actually is it?

First find out how much we have gained above our invested amount:
   earned amount - invested amount = 293,250 - 255,000 = 38,250 $

This seems like a quite nice sum but this is still not our net/clear income as we still need to pay the interest for the borrowed money which is:
   borrowed amount * interest rate percentage / 100 = 250,000 * 5 / 100 = 12,500 $

Once we pay this amount as well we'll get the clear income:
   investment return - interest for borrowed money = 38,250 - 12,500 = 25,750 $

So with our savings (5,000$) and borrowed money (250,000$) we've been able to earn 25,750$. As we return the borrowed money but keep the savings we now have:
   clear income + savings = 25,750 + 5,000 = 30,750$

This seems to be quite a nice year, don't you think?

Return percentage


Lets do some deeper analysis of how good we actually did.

At first we'll look what was the best/maximum percentage of return we could have achieved using this method.

To get this we'll find the difference of future gold price and its current price value:
   price in a year - price today = 115 - 100 = 15 $

And from this we find how big increase it actually is:
   (price difference / price today) * 100 = (15 / 100) * 100 = 15%

So 15% is the maximum we could have gained if we would use only our savings (and there would be no need to pay interest for borrowed money).
Which means that for each 100 $ we would earn 15% which is 15 $.

So if we would use just our savings we would gain: 5,000 * 15 / 100 = 750 $.

But as we were borrowing some money and we paid some interest rate, lets find out how good we actually did. For this purposes we use this calculation:
   (net income / invested amount) * 100 = (25,750 / 255,000) * 100 = 10.098 %

So lets summarize:
With using just our savings (5,000 $), we would have the highest return percentage (15%) but as only small amount would be invested, we would gained lower total income as well = 750 $.

With the borrowed money our total investment has increased rapidly (255,000 $) and although the return percentage was lower (10.098% - which is still regarded as good investment) our total income was much higher = 25,750 $.

It seems that it was a good decision to use not just our own savings but to borrow some money from bank as well.

Congratulations.

Other options - Call option


Now the question is: Can we do better than this?

Imagine that during our application for the bank loan, we would state that: I would like to buy gold bars because I expect their value to rise in a years time.

Our friendly banker would for some reason stop for a while. After a moment of deep thoughts he would tell us:
"I would have a proposal for you. Of course we will lend you the money. You're a good client as you already have 5,000 $ of your own, so I'm sure you'll be able to handle additional 250,000 $.
But why would you buy all of this gold right now, when instead I would offer you something better.

I can offer you the possibility to buy gold bars from us in a year for the same price as they costs today. So if the price of gold will be higher then today you'll earn some money. And the best thing is that if the price is lower there is no obligation for you to buy the gold bars from us, so you'll lose no more money at all. This seems really promising doesn't it? And to do so, all you have to do is sign this contract and pay the initial fee of 8 $ for each gold bar you'll be able to buy.""

Ok, so our friendly banker has offered us the possibility (but not the obligation) to buy something in the future for an agreed price. This is a contract which is normally known as 'Call Option'. The fee you have to pay for signing/entering this contract is known as 'Option Premium'.

So we have a new possibility now. But is it worth using this possibility? Let's do some math again to find it out.

First we'll find out how many 'Call options' can we actually buy:
   amount we have / option premium = 255,000 / 8 = 31,875 pieces

Now we have some amount of 'Options'. Lets imagine, that instead of buying the gold in years time for 100 $ and selling it back for 115 $ there are people who would buy our contracts for the price difference 15 $. So how much would we gain in the end:
   count of option calls * difference in gold price = 31,875 * 15 = 478,125 $

OMG, this is a horrendous sum. But remember we still need to subtract our invested amount and interest we need to pay for borrowed money to get the net/real income:
   investment return - invested amount - interest for borrowed money = 478,125 - 255,000 - 12,500 = 210,625 $

Holy macarony. This is way better than the previous 25,750 $. Lets see the actual percentage of return:
   (net income / invested amount) * 100 = (210,625 / 255,000) * 100 = 82.598 %

This seems like the best possible approach. We received much more money (210,625 $ instead of 25,750 $) as well as higher return percentage (82.598 % instead of 10.098 %).

The funny thing is that we could never achieve something like this with just buying gold on its own. Instead we were buying something that was derived from buying the gold. An option to buy the gold. Because of that we say that 'Call Option' is a 'Derivative'. There are many more 'Derivatives' that are being used, but for now just remember that 'Call Option' is one of them.

Negative scenario - possible losses explained


You might ask yourself. Why would the friendly banker ever provide us such an excellent opportunity? Aren't they only smiling on the outside but are rotten inside?

Well actually our friendly banker is nor good nor bad. All what he did is provided us the possibility to "multiply" the possible gain, but also (and this is important) the possible loss.

Let's imagine that all of the future traveling would be just a prank and the price of gold bar in years time would instead of rising by 15 $ to 115 $ actually fell by (only) 5 $ to 95 $.

How much would we actually loose?

We've already discussed few scenarios and each of them would have different losses:

a) if we would use only our savings

For 5,000 $ we could buy only 50 gold bars. In one years time the price of those gold bars would be:
   amount of gold bars * price of gold bar in a year = 50 * 95 = 4,750 $

So we would loose:
   earned amount - invested amount = 4,750 - 5,000 = -250 $

Which in percentages is a loss of:
   (clear loss / invested amount) * 100 = (250 / 5,000) * 100 = 5 %

b) if we would use savings and borrowed money

The actual price we would receive once selling the gold bars would be:
   amount of gold bars * price of gold bar in a year = 2,550 * 95 = 242,250 $

So the loss would be:
   earned amount - invested amount = 242,250 - 255,000 = -12,750 $

As we still need to pay the interest for borrowed money, our clear loss would be:
   investment difference + interest = 12,750 + 12,500 = 25,250 $

Which in percentages is a loss of:
   (clear loss / invested amount) * 100 = (25,250 / 255,000) * 100 = 9.902 %

This means that we would not even loose all of our savings, but beside this we would still need to pay back the dept of 20,250 $.

c) if we would call options with our savings and borrowed money

in this case we would actually loose everything. And by losing everything I mean we would loose our savings, borrowed money and would still need to return it plus the interest. The problem is that we used all the money to buy a promise which is now worthless. In situations before we at least had gold which was cheaper but still had SOME value and people would be willing to pay this smaller value for it. But now we only hold many papers which allow us to buy gold for higher value than we would get on the market. And nobody (with properly functioning mind) would pay us for this disadvantageous option. So in the end we would be in debt of:
   borrowed money + interest = 250,000 + 12,500 = 262,500 $

But remember, to get the net/real loss we still need to add our lost savings:
   262,500 + 5,000 = 267,500 $
 
Which in percentages is a loss of:
   (clear loss / invested amount) * 100 = (267,500 / 255,000) * 100 = 104.902 %

So as you can see, if this would be "only" a prank, it could be a very costly prank indeed.

Sunday, March 30, 2014

How paying the Highest market rates can Ruin Your Company

Although it may sound absurd, paying the highest market rates can actually ruin your company or project. And this is how it goes:

You have loads of money, starting a new project and want to attract the best guys on the market.

You will make sure your interview process is tough and will offer market rates nobody else can beat (let say 200 - 300 % of market average).

You hire the best guys, plus some guys that are not the best but can talk the talk.

Project started, there is a constructive progress and everybody is happy.

People realize more and more their high (money) status and know that they could never earn that same amount anywhere else.

People start spending their money and get used to their status. Project is still constructive.

After some time somebody will realize, that he would afraid of loosing this great job and he starts to be less constructively critical (as this could maybe threaten his position).

More and more people are less and less critical as they value the earnings more than the need to say what they think should be right.

After some time the project lead/manager/main architect will get used to situation where nobody (or just few) people express concerns regarding his ideas and will actually start to believe that he is always right (also he is earning a lot of money so he must be very good as well).

After some time he will believe so much in his true that he will be annoyed when somebody will oppose him.

The leading guy will have a bad idea (everybody can have a bad idea), but nobody or just a small amount of people will point to flaws of this suggestion.

The bad idea will be implemented. And the guys that will still have the will to point out the bad concepts behind the idea are seen as a threat (to the leading guys ego and to everybody else as being befriended with them could be regarded as risk to current position).

This repeats itself few times.

Now comes the point when the guys who actually still care are becoming frustrated because they realize they can't change things if they are heading the wrong directions.

The guys that care are leaving the project as they can't handle the frustration anymore.
The guys that don't care stay as the money is good.

You're left with a main guy (or guys) with boosted ego and no self control and bunch of people that don't want to oppose bad ideas, just want to do their work, get the check and go home.

More and more bad ideas are being implemented without any constructive conversation.

Project starts to have difficulties. You hire more guys.

Those that criticize the current state are seen as threat and its slowly taken care of them (they have some bad reviews and are being fired or are assimilated and became "silent workers").

After some time you just realize that you have a project that is extremely expensive and is producing (if ever) product of questionable quality and it seemed to get wrong on many levels.

And all of this because you provided rates nobody else could beat (so only those who cared about money stayed and the reasonable guys left).

End of the story.

Thursday, November 7, 2013

Testing multithreaded code

Sometimes you needed to test that your code is thread-safe and can be run from multiple threads at the same time. To help with doing this I wrote an utility class that can make your test code simpler and more readable.

Here is the usage of it. I was testing that SimpleDateFormat is thread safe (actually it is not so this test will fail):
public class SimpleDateFormatTest {

    // this test will fail as SimpleDateFormat is not thread safe
    @Test
    public void shouldWorkConcurrently() throws ExecutionException, InterruptedException {
        // Given
        final DateFormat dateFormat = new SimpleDateFormat();

        final Date date1 = newRandomDate();
        final Date date2 = newRandomDate();
        final Date date3 = newRandomDate();

        ConcurrentExecutor executor = new ConcurrentExecutor();

        Future<String> result1 = executor.addAction(new Callable<String>() {
            public String call() {

                return dateFormat.format(date1);
            }
        });
        Future<String> result2 = executor.addAction(new Callable<String>() {
            public String call() {

                return dateFormat.format(date2);
            }
        });
        Future<String> result3 = executor.addAction(new Callable<String>() {
            public String call() {

                return dateFormat.format(date3);
            }
        });

        // When
        executor.executeAtTheSameTime(); // this will block until all actions are finished

        // Then
        assertThat(result1.get(), is(new SimpleDateFormat().format(date1)));
        assertThat(result2.get(), is(new SimpleDateFormat().format(date2)));
        assertThat(result3.get(), is(new SimpleDateFormat().format(date3)));
    }

    private Date newRandomDate() {
        return new Date(new Random().nextLong());
    }
}
In this test I created a ConcurrentExecutor to which I added 3 actions. Each of those actions calls the format method for one of 3 dates. Then I call the method executeAtTheSameTime which will make sure that all actions will start at the same time. Once the execution is finished I retrieve each result and verify that it is the same as proper single threaded conversion.

One nice thing about this utility is that it is extremely simple to retry the execution. Just rerun the executeAtTheSameTime and the Future results will hold a new value. This way you can put the When and Then section info a for loop and test the execution thread safety multiple times. This is sometimes needed as some multi-threaded issues are not always visible during the first run.

If you would like to add this utility into your project here is the actual implementation of ConcurrentExecutor (please note that it is in java 1.7 so if you're using some older version you might miss some generics definitions):
public class ConcurrentExecutor {

    private List<Callable<?>> actions = new ArrayList<>();
    private List<Object> results = new ArrayList<>();

    private volatile boolean finished = false;

    public <T> Future<T> addAction(Callable<T> callable) {
        actions.add(callable);
        int actionIndex = actions.size() - 1;
        return new FutureResult<>(actionIndex);
    }

    public void executeAtTheSameTime() {
        try {
            finished = false;
            results.clear();

            ExecutorService executor = Executors.newFixedThreadPool(actions.size());

            CyclicBarrier barrier = new CyclicBarrier(actions.size());
            CountDownLatch doneCountDown = new CountDownLatch(actions.size());

            List<Future<?>> futureResults = new ArrayList<>();
            for (Callable<?> action : actions)
            {
                futureResults.add(executor.submit(new ActionCallable<>(action, barrier, doneCountDown)));
            }
            doneCountDown.await();

            for (Future<?> futureResult : futureResults)
            {
                try
                {
                    results.add(futureResult.get(500, TimeUnit.MILLISECONDS));
                }
                catch (Exception e)
                {
                    throw new RuntimeException("not able to retrieve result from thread execution", e);
                }
            }

            executor.shutdownNow();

            finished = true;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    class ActionCallable<T> implements Callable<T> {

        private final Callable<T> action;
        private final CyclicBarrier startBarrier;
        private final CountDownLatch doneCountDown;

        ActionCallable(Callable<T> action, CyclicBarrier startBarrier, CountDownLatch doneCountDown) {
            this.action = action;
            this.startBarrier = startBarrier;
            this.doneCountDown = doneCountDown;
        }

        @Override
        public T call() throws Exception {
            T result;

            startBarrier.await();
            result = action.call();
            doneCountDown.countDown();

            return result;
        }
    }

    class FutureResult<T> implements Future<T> {

        private final int resultIndex;

        public FutureResult(int resultIndex) {
            this.resultIndex = resultIndex;
        }

        @Override
        public boolean isDone() {
            return finished;
        }

        @Override
        @SuppressWarnings("unchecked")
        public T get() throws InterruptedException, ExecutionException {
            if (!isDone()) {
                throw new IllegalStateException("execution has not yet finished");
            }
            return (T) results.get(resultIndex);
        }

        @Override
        public boolean cancel(boolean mayInterruptIfRunning) {
            throw new RuntimeException("not implemented by intention");
        }

        @Override
        public boolean isCancelled() {
            throw new RuntimeException("not implemented by intention");
        }

        @Override
        public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
            throw new RuntimeException("not implemented by intention");
        }
    }
}

Thursday, October 31, 2013

Testing QuickFix/J messages

Some short time ago we've been using QuickFix/J for sending and receiving messages. The library was ok, but to write tests for it was kind of painfull. For example our verification of created messages looked like this:
assertThat(message, instanceOf(AllocationInstruction.class));
assertThat(message.getHeader().getString(SenderSubID.FIELD), is("senderSubId-123"));
assertThat(message.getString(AllocID.FIELD), is("allocId-123"));
assertThat(message.getInt(AllocType.FIELD), is(AllocType.CALCULATED));
assertThat(message.getChar(AllocTransType.FIELD), is(AllocTransType.NEW));
assertThat(message.getDecimal(Shares.FIELD), is(new BigDecimal("1000000")));

assertThat(message.getInt(NoAllocs.FIELD), is(2));

AllocationInstruction.NoAllocs allocationGroup;
allocationGroup = (AllocationInstruction.NoAllocs) message.getGroup(1, new AllocationInstruction.NoAllocs());
assertThat(allocationGroup.getString(IndividualAllocID.FIELD), is("1"));
assertThat(allocationGroup.getString(AllocAccount.FIELD), is("acc-01"));
assertThat(allocationGroup.getDecimal(AllocShares.FIELD), is(new BigDecimal("250000")));

allocationGroup = (AllocationInstruction.NoAllocs) message.getGroup(2, new AllocationInstruction.NoAllocs());
assertThat(allocationGroup.getString(IndividualAllocID.FIELD), is("2"));
assertThat(allocationGroup.getString(AllocAccount.FIELD), is("acc-02"));
assertThat(allocationGroup.getDecimal(AllocShares.FIELD), is(new BigDecimal("750000")));
The code was not very readable and we also had to catch FieldNotFound exception each time we were doing this. To resolve this inconvenience I've created my own hamcrest matcher that can be used like this:
assertThat(message, isFIXMessage()
        .ofType(AllocationInstruction.class)
        .with(header().with(SenderSubID.FIELD, "senderSubId-123"))
        .with(AllocID.FIELD, "allocId-123")
        .with(AllocType.FIELD, AllocType.CALCULATED)
        .with(AllocTransType.FIELD, AllocTransType.NEW)
        .with(Shares.FIELD, "1000000")
        .with(NoAllocs.FIELD, 2)
        .with(group(1, NoAllocs.FIELD)
                .with(IndividualAllocID.FIELD, 1)
                .with(AllocAccount.FIELD, "acc-01")
                .with(AllocShares.FIELD, new BigDecimal("250000"))
        )
        .with(group(2, NoAllocs.FIELD)
                .with(IndividualAllocID.FIELD, 2)
                .with(AllocAccount.FIELD, "acc-02")
                .with(AllocShares.FIELD, new BigDecimal("750000"))
        )
);
The source code can be found/is stored under my project: QuickFixUtils.

Monday, March 12, 2012

Parsing JBehave tables

This is a simple sample how to parse JBehave tables.

In our project we often have to parse JBehave tables that might look like this one:

Given currencies are truncated to these decimal places
| Currency | Decimal places |
| USD | 2 |
| JPY | 0 |
| LYD | 3 |

The standard approach is to write something like this

@Given("currencies are truncated to these decimal places $currencyDecimalPlaces")
public void currencyDecimalPlaces(ExamplesTable currencyDecimalPlacesTable) {
...
for (Parameters row : currencyDecimalPlacesTable.getRowsAsParameters()) {
// read row data
}
...
}

where reading row data may look like this:

CurrencyCode currencyCode = row.valueAs("Currency", CurrencyCode.class);
Integer decimalPlaces = row.valueAs("Decimal places", Integer.class);

or we can make it a little more readable like this:

CurrencyCode currencyCode = Currency.in(row);
Integer decimalPlaces = DecimalPlaces.in(row);

To make the readable code we define a new Column class:

public class Column<T> {

private final String label;
private final Class<T> defaultType;


public Column(String label, Class<T> defaultType) {
this.label = label;
this.defaultType = defaultType;
}


public <T> T in(Parameters row, Class<T> type) {
return row.valueAs(label, type);
}


public T in(Parameters row) {
return in(row, defaultType);
}


public String asString(Parameters row) {
return in(row, String.class);
}


public static <T> Column<T> column(String label, Class<T> defaultType) {
return new Column<T>(label, defaultType);
}


public static Column<String> column(String label) {
return new Column<String>(label, String.class);
}
}

and registering custom columns:

public interface Columns {

...

public static final Column<CurrencyCode> Currency = column("Currency", CurrencyCode.class);
public static final Column<Integer> DecimalPlaces = column("Decimal places", Integer.class);

...
}

now we can convert the column to the default registered class

CurrencyCode currencyCode = Currency.in(row);

or to a specified class:

String currencyCode = Currency.in(row, String.class);

Thursday, September 1, 2011

The irony of not testing

Some time ago I wanted to do something with jQuery. But our customer was still using a really obsolete version: 1.1.3.1 that has been released in 2008. At that time the last stable version was 1.6 and the functionality I needed was introduced in jQuery 1.3. As I had no intention to write something that has been already written (and fixed multiple times over its existence) I asked the the leading programmer of this project if there would be a slight chance of replacing it (jQuery) with a newer version.

The answer was simple: "NO". As strange it may sound I kind of undestood him and it wasn't a suprise for me. It was just a sad realization of the truth. To change the jQuery library I needed to upload it into the core module, that has then been referenced by 9 other big modules (that depended on him). And as NONE of these 9 modules had automated tests of their behavior, no one would know if this change would introduce some bugs or not (they already had workaround and fixes for the old jQuery version and god knows how it would interact with the latest version). So if you look at it: my small task/requirement could have killed all 9 modules that have been nicely working for at least 3 years (and it would require regression tests for EVERYTHING which was extremely costly).

The irony was that the lack of useful tests might forced me into introducing some custom code that was not mature enough (from performance and memory consumption view) and probably buggy (even with some testing) instead of just using some standard code that has been proven with time and repaired/maintained constantly.

The lesson learned from this is: test your code as without it your code might become so big that the task of testing will take a whole year for you (because you need to learn all the business logic behind it to see that this strange behavior is the correct one). As without tests : you might be unable to upgrade your existing libraries and will be forced to create custom workarounds for something that has been already done by somebody else. And in comparison to your code the existing one might be more performant, mature AND under active maintenance.

Sunday, July 24, 2011

Spring proxy - calling methods within the same service

One of the bigest issues of spring aop is, that when you use its proxies for adding some aop functionality (like for example transactions or security), your calls to a method withing the same bean won't trigger the advised aop functionality.

So if you have a Service, that has two methods, where method A() HAS NO @Transactional annotation and method B() HAS a @Transactional annotation and non transactional method A() calls during its execution transactional method B() then spring won't start any transaction. This is because the spring proxy will redirect its call for A() to the service object but the call to B() won't be executed on the proxy (that knows how and when to start the transaction) but instead on the actual service object that has not functional code to start the transaction (only a @Transactional annotation on the method B()).

To overcome this problem I have implemented a simple solution that injects the proxy of current bean instance and then you execute advised methods calling this instance proxy variable. All you have use is a @ThisInstance annotation and register a custom BeanPostProcessor:
<bean class="sk.yourpackage.ThisInstanceBeanPostProcessor"/>
After this you annotate a setter or field with @ThisInstance annotation and spring will inject a proxy instance of this bean as a setter parameter or field value (if a proxy won't be created it will inject the actual unproxied service). Like for example:
@ThisInstance
private MyService thisInstance;
After this you change your code from:
this.B();
into
thisInstance.B();
And that is the whole configuration. It works for private, protected, ... method and fields and for beans with any scoping.
 
This is the code of the annotation:
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.METHOD})
public @interface ThisInstance { }
and this is the code for bean post processor:
public class ThisInstanceBeanPostProcessor implements BeanPostProcessor, Ordered {

private final Set<Class<? extends Annotation>> annotationTypes = new LinkedHashSet<Class<? extends Annotation>>();

private int order = Ordered.LOWEST_PRECEDENCE;


public ThisInstanceBeanPostProcessor() {
this.annotationTypes.add(ThisInstance.class);
}


@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}


@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {

Object targetBean = getTargetBean(bean);

injectCurrentInstance(targetBean, bean);

return bean;
}


private Object getTargetBean(Object bean) {
Object target = bean;

if (target instanceof Advised) {
target = ((Advised) target).getTargetSource();

if (target instanceof TargetSource) {
try {
target = ((TargetSource) target).getTarget();
} catch (Exception e) {
throw new IllegalStateException(e);
}
}
}

return target;
}


private void injectCurrentInstance(Object targetBean, Object thisInstance) {

if (annotationTypes.size() == 0) {
return;
}

Class<?> beanClass = targetBean.getClass();

do {
// for each interface - look for injection annotations
for (Class beanInterface : beanClass.getInterfaces()) {
for (Method method : beanInterface.getMethods()) {
for (Class<? extends Annotation> annotationType : annotationTypes) {
if (method.getAnnotation(annotationType) != null) {
invokeMethod(targetBean, method, thisInstance);
break;
}
}
}
}

// for each method - look for injection annotations
for (Method method : beanClass.getDeclaredMethods()) {
for (Class<? extends Annotation> annotationType : annotationTypes) {
if (method.getAnnotation(annotationType) != null) {
invokeMethod(targetBean, method, thisInstance);
break;
}
}
}

// for each field - look for injection annotations
for (Field field : beanClass.getDeclaredFields()) {
for (Class<? extends Annotation> annotationType : annotationTypes) {
if (field.getAnnotation(annotationType) != null) {
setFieldValue(targetBean, field, thisInstance);
break;
}
}
}

beanClass = beanClass.getSuperclass();

} while (!Object.class.equals(beanClass));
}


private void invokeMethod(Object object, Method method, Object... values) {
boolean isAccessible = method.isAccessible();

try {
method.setAccessible(true);

method.invoke(object, values);
} catch (Exception e) {
throw new IllegalStateException(e);
} finally {
method.setAccessible(isAccessible);
}
}


private void setFieldValue(Object object, Field field, Object value) {
boolean isAccessible = field.isAccessible();

try {
field.setAccessible(true);

field.set(object, value);
} catch (Exception e) {
throw new IllegalStateException(e);
} finally {
field.setAccessible(isAccessible);
}
}


/**
* allows you to add custom annotation type
*
* @param annotationType custom annotation type
*/
public void setAnnotationType(Class<? extends Annotation> annotationType) {
this.annotationTypes.add(annotationType);
}


/**
* allows you to define custom annotation types
*
* @param annotationTypes custom annotation types
*/
public void setAnnotationTypes(Set<Class<? extends Annotation>> annotationTypes) {
this.annotationTypes.clear();
this.annotationTypes.addAll(annotationTypes);
}


@Override
public int getOrder() {
return order;
}


public void setOrder(int order) {
this.order = order;
}
}