dimanche 9 décembre 2018

Iterate Fields of Fields continuously

Please avoid giving answers in Kotlin only and higher than Android 21.

I'm trying to build an API parser that makes use of class hierarchy logic to represent the API hierarchy itself. With this structure I am able to parse the API in an uncomplicated fashion and I was able to achieve this already, but I'd like to improve it further.

I'll begin explaining what I already have implemented.

This is an example URL that my app will receive via GET, parse and dispatch internally:

http://www.example.com/news/article/1105

In the app the base domain is irrelevant, but what comes after is the API structure.

In this case we have a mixture of commands and variables:

  • news (command)
  • article (command)
  • 1105 (variable)

To establish what is a command and what is a variable I built the following class structures:

public class API {
    public static final News extends AbstractNews {}
}

public class AbstractNews {
    public static final Article extends AbstractArticle {}
}

public class Article {
    public static void GET(String articleId) {
        // ...
    }
}

And I iterate through each class after splitting the URL while matching each command to each class (or subclass) starting from the API class. Until I reach the end of the split URL any matches that fail are stored in a separate list as variables.

The process is as follows for the example provided above:

Split URL each forward slash (ignoring the base domain)

/news/article/1105

List<String> stringList = [
    news, 
    article,
    1105
];

Iterate each item in the split list and match agains the API structured classes (the following is just a sample example, it is not 100% of what I currently have implemtend):

List<String> variableList = new ArrayList<>();
Class lastClass = API.class;

for (String stringItem : stringList) {

    if ((lastClass = classHasSubClass(lastClass, stringItem)) != null) {
        continue;
    }

    variableList.add(stringItem);

}

Once the end of the list is reached I check if the last class contains the request method (in this case GET) and invoke along with the variable list.

Like I said before this is working perfectly fine, but it leaves every class directly exposed and as a result they can be accessed directly and incorrectly by anyone else working on the project, so I am trying to make the hierarchy more contained.

I want to keep the ability to access the methods via hierarchy as well, so the following can still be possible:

API.News.Article.GET(42334);

While at the same time I don't want it to be possible to do the following as well:

AbstractArticle.GET(42334);

I have tried making each subclass into a class instance field instead

public class API {
    // this one is static on purpose to avoid having to instantiate
    // the API class before accessing its fields
    public static final AbstractNews News = new AbstractNews();
}

public class AbstractNews {
    public final AbstractArticle Article = new AbstractArticle();
}

public class Article {
    public void GET(String articleId) {
        // ...
    }
}

This works well for the two points I wanted to achieve before, however I am not able to find a way to iterate the class fields in a way that allows me to invoke the final methods correctly.

For the previous logic all I needed to iterate was the following:

private static Class classHasSubClass(Class<?> currentClass, String fieldName) {

    Class[] classes;

    classes = currentClass.getClasses();

    for (final Class classItem : classes) {
        if (classItem.getSimpleName().toLowerCase().equals(fieldName)) {
            return classItem;
        }
    }

    return null;

}

But for the second logic attempt with fields I was not able to invoke the final method correctly, probably because the resulting logic was in fact trying to do the following:

AbstractArticle.GET(42334);

Instead of

API.News.Article.GET(42334);

I suspect it is because the first parameter of the invoke method can no longer be null like I was doing before and has to be the correct equivalent of API.News.Article.GET(42334);

Is there a way to make this work or is there a better/different way of doing this?





Aucun commentaire:

Enregistrer un commentaire