Почему не возможно расширить аннотации в Java?

Создайте контроллер в папке приложения / контроллеров.

class Error extends Controller
{
function error_404()
{
    $this->load->view('error');
}
}

Затем в вашем приложении / библиотеке расширьте класс Router, создав application / library / MY_Router.php

class MY_Router extends CI_Router
{
private $error_controller = 'error';
private $error_method_404 = 'error_404';

function MY_Router()
{
    parent::CI_Router();
}

// this is just the same method as in Router.php, with show_404() replaced by $this->error_404();
function _validate_request($segments)
{
    // Does the requested controller exist in the root folder?
    if(file_exists(APPPATH.'controllers/'.$segments[0].EXT))
    {
        return $segments;
    }

    // Is the controller in a sub-folder?
    if(is_dir(APPPATH.'controllers/'.$segments[0]))
    {
        // Set the directory and remove it from the segment array
        $this->set_directory($segments[0]);
        $segments = array_slice($segments, 1);
        if(count($segments) > 0)
        {
            // Does the requested controller exist in the sub-folder?
            if(!file_exists(APPPATH.'controllers/'.$this->fetch_directory().$segments[0].EXT))
            {
                return $this->error_404();
            }
        }
        else
        {
            $this->set_class($this->default_controller);
            $this->set_method('index');
            // Does the default controller exist in the sub-folder?
            if(!file_exists(APPPATH.'controllers/'.$this->fetch_directory().$this->default_controller.EXT))
            {
                $this->directory = '';
                return array();
            }
        }
        return $segments;
    }
    // Can't find the requested controller...
    return $this->error_404();
}

function error_404()
{
    $segments = array();
    $segments[] = $this->error_controller;
    $segments[] = $this->error_method_404;
    return $segments;
}

function fetch_class()
{
    // if method doesn't exist in class, change
    // class to error and method to error_404
    $this->check_method();
    return $this->class;
}

function check_method()
{
    $class = $this->class;
    if (class_exists($class))
    {
        if ($class == 'doc')
        {
            return;
        }
        if (! in_array('_remap', array_map('strtolower', get_class_methods($class)))
            && ! in_array(strtolower($this->method), array_map('strtolower', get_class_methods($class))))
        {
            $this->class = $this->error_controller;
            $this->method = $this->error_method_404;
            include(APPPATH.'controllers/'.$this->fetch_directory().$this->error_controller.EXT);
        }
    }
}

}

Если страница не существует, она будет быть направленным на контроллер ошибок

223
задан Andrew Brēza 12 August 2017 в 21:38
поделиться

6 ответов

О причине, по которой он не был разработан таким образом, вы можете найти ответ в JSR 175 FAQ по дизайну, где сказано:

Почему бы и нет вы поддерживаете подтип аннотации (когда один тип аннотации расширяет другой)?

Это усложняет тип аннотации система, и делает ее намного больше сложно написать «Особые инструменты».

«Особые инструменты» - программы, которые запрашивают известные типы аннотаций произвольного внешние программы. Генераторы заглушки, например, попадают в эту категорию. Эти программы будут читать аннотированные классы, не загружая их в виртуальная машина, но загрузится интерфейсы аннотаций.

Итак, да, думаю, причина в том, что это просто KISS. В любом случае, похоже, что эта проблема (наряду со многими другими) рассматривается как часть JSR 308 , и вы даже можете найти альтернативный компилятор с этой функциональностью, уже разработанный Матиасом Рикеном .

161
ответ дан 23 November 2019 в 04:00
поделиться

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

1
ответ дан 23 November 2019 в 04:00
поделиться

Extensible annotations would effectively add the burden of specifying and maintaing another type system. And this would be a fairly unique type system, so you could not simply apply an OO type paradigm.

Think through all the issues when you introduce polymorphism and inheritance to an annotation (e.g. what happens when sub-annotation changes meta-annotation specs such as retention?)

And all this added complexity for what use-case?

You want to know if a given annotation belongs to a category?

Try this:

@Target(ElementType.ANNOTATION_TYPE)
public @interface Category {
    String category();
}

@Category(category="validator")
public @interface MyFooBarValidator {

}

As you can see, you can easily group and categorize annotations without undue pain using the provided facilities.

So, KISS is the reason for not introducing a meta-type type system to the Java language.

[ps edit]

Я использовал String просто для демонстрации и ввиду открытой метааннотации. Очевидно, что для вашего собственного проекта вы можете использовать перечисление типов категорий и указать несколько категорий («множественное наследование») для данной аннотации. Обратите внимание, что значения являются полностью поддельными и предназначены только для демонстрационных целей:

@Target(ElementType.ANNOTATION_TYPE)
public @interface Category {
    AnnotationCategory[] category();
}
public enum AnnotationCategory {
    GENERAL,
    SEMANTICS,
    VALIDATION,
    ETC
}

@Category(category={AnnotationCategory.GENERAL, AnnotationCategory.SEMANTICS})
public @interface FooBarAnnotation {

}

69
ответ дан 23 November 2019 в 04:00
поделиться

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

В вашем примере с валидатором вы можете просто получить аннотированный тип в аннотации и увидеть если у него есть метааннотация валидатора.

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

12
ответ дан 23 November 2019 в 04:00
поделиться

Одна вещь, о которой я мог подумать, - это возможность иметь несколько аннотаций. Таким образом, вы можете добавить валидатор и более конкретную аннотацию в одно и то же место. Но могу ошибаться :)

2
ответ дан 23 November 2019 в 04:00
поделиться

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

О вашем примере с аннотацией 'validator' - тогда вы можете использовать подход 'meta-annotation' . Т.е. вы применяете конкретную метааннотацию ко всему интерфейсу аннотации.

2
ответ дан 23 November 2019 в 04:00
поделиться
Другие вопросы по тегам:

Похожие вопросы: