<repo_name>nycjv321/reflection<file_sep>/src/test/java/com/nycjv321/reflection/MessageTest.java
package com.nycjv321.reflection;

import com.nycjv321.reflection.exceptions.MessageMissingException;
import org.testng.annotations.Test;

import javax.jws.WebParam;

import static org.testng.Assert.*;

/**
 * Created by <NAME> <<EMAIL>> on 12/9/16.
 */
public class MessageTest {

    private final Receiver<TestClass> receiver = Receiver.of(TestClass.class);
    private Message message;

    @Test(dependsOnGroups = "receiver", groups = "messages")
    public void on() {
        message = receiver.on("stuff");
        assertNotNull(message);
    }

    @Test(dependsOnMethods = "on", dependsOnGroups = "receiver", groups = "messages", expectedExceptions = MessageMissingException.class)
    public void onNull() {
        receiver.on("Meep!");
    }


    @Test(dependsOnMethods = "on", dependsOnGroups = "receiver", groups = "messages", expectedExceptions = MessageMissingException.class)
    public void onNullWithArguments() {
        receiver.on("Meep!", boolean.class);
    }

    @Test(dependsOnMethods = "on", dependsOnGroups = "receiver", groups = "messages")
    public void annotation() {
        assertFalse(
            message
                    .get(Test.class)
                .enabled()
        );
    }

    @Test(dependsOnMethods = "on", dependsOnGroups = "receiver", groups = "messages")
    public void isFinal() {
        assertTrue(
                Receiver
                    .of(TestClass.class)
                    .isFinal("stuff",String.class)
        );
    }

    /**
     * Once we know {@code Receiver#on} works on methods without arguments,
     * let's update our test message to represent messages that include arguments
     * (∩｀-´)⊃━☆ﾟ.*･｡ﾟ
     */
    @Test(dependsOnMethods = "on", dependsOnGroups = "receiver", groups = "messages")
    public void onWithArgument() {
        message = Receiver
                .of(TestClass.class)
                .on("stuff", String.class);
        assertNotNull(message);
    }


    @Test(dependsOnMethods = "onWithArgument", dependsOnGroups = "receiver", groups = "messages")
    public void argumentAnnotation() {
        assertTrue(
                message
                .argumentAnnotation(WebParam.class)
                .header()
        );
    }

    @Test(dependsOnMethods = "onWithArgument", dependsOnGroups = "receiver", groups = "messages")
    public void argumentAnnotationPredicate() {
        assertNull(message.argumentAnnotation(WebParam.class, webParam -> !webParam.header()));
    }


    @Test(dependsOnMethods = "onWithArgument", dependsOnGroups = "receiver", groups = "messages")
    public void argument() {
        assertNotNull(message.criterion("arg"));
    }

}<file_sep>/README.md
# Reflection
This project provides a set of fluent APIs for performing reflection.

## About

This project aims to provide a straight forward, human friendly api to perform reflective operations.

The goal of this project is to provide the necessary support to test annotation configuration. 
Keeping this in mind, you may notice the current API focuses around Class, Method, and Parameter annotations. 

## Dependencies

- `com.intellij.annotations` - used to establish potential nullity
- `Java 8`

## Example Usage

Take a look at the unit tests. Current coverage is at `100%`!
 
If you're too impatient to look at the unit tests (shame on you), See below:

    // Extract the "arg" parameter's WebParam annotation. 
    // This metadata is found on the TestClass#stuff(String arg) method.
    Receiver
        .of(TestClass.class)
        .on("stuff", String.class)
        .criterion("arg").get(WebParam.class);
        
### Domain Language
In this API, abstractions of classes (T) are referred to Receivers of type T. 

     new Receiver<T>(clazz); // class representing a definition of T
     
Methods and their parameters are referred to as messages. To better understand methods as messages, take a look [here](https://en.wikipedia.org/wiki/Object-oriented_programming#Dynamic_dispatch.2Fmessage_passing).

Method parameters are referred to as "criterion". If this code is compiled using Java 8 and includes the `-parameters` argument, you can refer to parameters by name. See first example.
       
Alternatively, you may "search" for arguments. For example:

    Receiver.of(TestClass.class)
        .on("stuff", String.class)
        .argumentAnnotation(WebParam.class, webParam -> !webParam.header());
        
In the above example, we search for an argument's WebParam annotation where the WebParam#header() is false. 
The `Predicate` is an optional argument.
<file_sep>/src/main/java/com/nycjv321/reflection/Criterion.java
package com.nycjv321.reflection;


import org.jetbrains.annotations.Nullable;

import java.lang.annotation.Annotation;
import java.lang.reflect.Parameter;

/**
 * Created by <NAME> <<EMAIL>> on 12/9/16.
 */
public final class Criterion implements Describable {
    private final Parameter parameter;

    Criterion(Parameter parameter) {
        this.parameter = parameter;
    }

    @Override
    @Nullable
    public <T extends Annotation> T get(Class<T> annotation) {
        return this.parameter.getAnnotation(annotation);
    }
}
<file_sep>/src/main/java/com/nycjv321/reflection/Describable.java
package com.nycjv321.reflection;

import java.lang.annotation.Annotation;

/**
 * Created by <NAME> <<EMAIL>> on 12/18/16.
 */
public interface Describable {

    <T extends Annotation> T get(Class<T> annotation);

}
<file_sep>/src/test/java/com/nycjv321/reflection/ReceiverTest.java
package com.nycjv321.reflection;


import org.testng.annotations.Test;

import static org.testng.Assert.*;

/**
 * Created by <NAME> <<EMAIL>> on 12/9/16.
 */
public class ReceiverTest {

    private Receiver<TestClass> receiver;

    @Test(groups = "receiver")
    public void of() throws Exception {
        receiver = Receiver.of(TestClass.class);
        assertNotNull(receiver);
    }

    @Test(dependsOnMethods = "of", groups = "receiver")
    public void isFinal() throws Exception {
        assertTrue(receiver.isFinal());
    }

    @Test(dependsOnMethods = "of", groups = "receiver")
    public void get() throws Exception {
        Test test = receiver.get(Test.class);
        assertNotNull(test);
        assertFalse(test.enabled());
    }

    @Test(dependsOnMethods = "get", groups = "receiver")
    public void getNull() throws Exception {
        assertNull(receiver.get(Deprecated.class));
    }

}