Итерация полей полей непрерывно с отражением - PullRequest
0 голосов
/ 09 декабря 2018

Пожалуйста, избегайте давать ответы только на Kotlin и выше, чем Android 21.

Я пытаюсь создать синтаксический анализатор API, который использует логику иерархии классов для представления самой иерархии API.С этой структурой я могу анализировать API несложным способом, и я уже смог достичь этого, но я хотел бы улучшить его дальше.

Я начну объяснять, что я уже реализовал.

Это пример URL, который мое приложение будет получать через GET, анализировать и отправлять его внутренне:

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

В приложении базовый домен не имеет значения, но послеСтруктура API.

В этом случае мы имеем смесь команд и переменных:

  • news (команда)
  • article (команда)
  • 1105 (переменная)

Чтобы установить, что такое команда и что такое переменная, я построил следующие структуры классов:

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) {
        // ...
    }
}

И я перебираю каждый класс после разделения URLсопоставляя каждую команду с каждым классом (или подклассом), начиная с класса API.До тех пор, пока я не достигну конца разделенного URL-адреса, любые несоответствия сохраняются в отдельном списке как переменные.

Для приведенного выше примера процесс выглядит следующим образом:

Разделение URL-адреса каждый слеш(игнорируя базовый домен)

/news/article/1105

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

Выполните итерацию каждого элемента в разделенном списке и сопоставьте вновь структурированные классы API (ниже приведен лишь пример примера, это не 100% от того, что я в настоящее время реализую):

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

for (String stringItem : stringList) {

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

    variableList.add(stringItem);

}

Как только достигнут конец списка, я проверяю, содержит ли последний класс метод запроса (в данном случае GET), и вызываю вместе со списком переменных.

Как я уже говорил ранее, это работает совершенно нормально, но при этом все классы становятся доступными напрямую, и в результате к ним могут обращаться напрямую и неправильно все, кто работает над проектом, поэтому я пытаюсь сделать иерархию более содержательной.

Я хочу сохранить возможность доступа к методам также через иерархию, поэтому все еще возможно следующее:

API.News.Article.GET(42334);

Хотя в то же время я не хочу, чтобы было возможно сделать также следующее:

AbstractArticle.GET(42334);

Я попытался превратить каждый подкласс в поле экземпляра класса вместо

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) {
        // ...
    }
}

Это хорошо работает для двух моментов, которые я хотел достичь ранее, однако я не могу найти способ итерации полей класса таким образом, чтобы я мог правильно вызывать финальные методы.

Для предыдущей логики все, что мне нужно было повторить, было следующее:

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;

}

Но для второй логической попытки с полями я не смог правильно вызвать последний метод, вероятно, потому что полученная логика была вфакт, пытающийся сделать следующее:

AbstractArticle.GET(42334);

Вместо

API.News.Article.GET(42334);

Я подозреваю, что это потому, что первый параметр метода invoke больше не может быть null, как яделал раньше и должен быть правильным эквивалентом API.News.Article.GET(42334);

Есть ли способ сделать эту работу или есть лучший / другой способ сделать это?

1 Ответ

0 голосов
/ 10 декабря 2018

Я обнаружил, что находился на правильном пути с полями экземпляра, но в конце пропустил часть необходимой информации для правильного вызова метода.

При итерации полей я использовал только класскаждого поля, которое раньше прекрасно работало со статическими ссылками на классы, так как эти экземпляры не были экземплярами, но теперь для правильной работы требуется экземпляр поля.

В конце концов, использовался метод итерациивместо classHasSubClass, который заставил это работать, выглядит следующим образом:

private static Object getFieldClass(Class<?> currentClass, Object currentObject, final String fieldName) {

    Field[] fieldList;

    fieldList = currentClass.getDeclaredFields();

    for (final Field field : fieldList) {
        if (field.getName().toLowerCase().equals(fieldName)) {

            try {
                return field.get(currentObject);
            } catch (IllegalAccessException e) {

                e.printStackTrace();
                break;

            }

        }
    }

    return null;

}

При этом я всегда сохраняю ссылку объекта экземпляра на последнее поле, которое я хочу вызвать для передачи в качестве 1-го параметра (someMethod.invoke(objectInstance);) вместо null.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...