Требуется конструктор по умолчанию в Java? - PullRequest
12 голосов
/ 19 ноября 2009

Есть ли способ требовать , чтобы класс имел конструктор по умолчанию (без параметров), помимо от использования проверки отражения, как показано ниже? (следующее будет работать, но оно будет хакерским и медленное отражение)

 boolean valid = false;
 for(Constructor<?> c : TParse.class.getConstructors())
 {
   if(c.getParameterTypes().length == 0) {
      valid = true;
      break; 
   }
 }
 if(!valid)
    throw new MissingDefaultConstructorException(...);

Ответы [ 3 ]

22 голосов
/ 19 ноября 2009

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

Вот пример кода (хотя я его не запускал):

@SupportedAnnotationTypes("*")   // needed to run on all classes being compiled
@SupportedSourceVersion(SourceVersion.RELEASE_6)
public class DefaultConstructor extends AbstractProcessor {

    @Override
    public boolean process(Set<? extends TypeElement> annotations,
            RoundEnvironment roundEnv) {

        for (TypeElement type : ElementFilter.typesIn(roundEnv.getRootElements())) {
            if (requiresDefaultConstructor(type))
                checkForDefaultConstructor(type);
        }
        return false;
    }

    private void checkForDefaultConstructor(TypeElement type) {
        for (ExecutableElement cons :
            ElementFilter.constructorsIn(type.getEnclosedElements())) {
            if (cons.getParameters().isEmpty())
                return;
        }

        // Couldn't find any default constructor here
        processingEnv.getMessager().printMessage(
                Diagnostic.Kind.ERROR, "type is missing a default constructor",
                type);
    }

    private boolean requiresDefaultConstructor(TypeElement type) {
        // sample: require any JPA Entity to have a default constructor
        return type.getAnnotation(Entity.class)) != null
               || type.getQualifiedName().toString().contains("POJO");
    }

}

Процессор аннотаций становится еще проще, если вы вводите аннотацию (например, требует аннотацию по умолчанию).

Заявление о необходимости иметь квалификатор по умолчанию

:: Я также предполагаю, что ОП запрашивает механизм, который предотвращает случайные ошибки для разработчиков, особенно написанные кем-то другим.

Должен существовать механизм для объявления того, для каких классов требуется процессор по умолчанию. Надеюсь, у вас уже есть критерии для этого, будь то шаблон в имени, шаблон в классификаторе, возможная аннотация и / или базовый тип. В приведенном выше примере вы можете указать критерии в методе requiresDefaultConstructor(). Вот пример того, как это можно сделать:

  1. На основе шаблона имени. TypeElement предоставить доступ к полному имени и имени пакета.

    return type.getQualifiedName().toString().contains("POJO");
    
  2. На основе аннотации, представленной в объявлении типа. Например, все классы Java Bean Entity должны иметь конструкторы не по умолчанию

    return type.getAnnotation(Entity.class) != null;
    
  3. На основе абстрактного класса или интерфейса.

    TypeElement basetype = processingEnv.getElements().getTypeElement("com.notnoop.mybase");
    return processingEnv.getTypes().isSubtype(type.asType(), basetype.asType());
    
  4. [Рекомендуемый подход]: Если вы используете интерфейс базового типа, я рекомендую смешать подход аннотации с интерфейсом базового типа. Вы можете объявить аннотацию, например, MyPlain вместе с метааннотацией: @Inherited. Затем вы можете аннотировать базовый тип этой аннотацией, тогда все подклассы также наследуют аннотацию. Тогда ваш метод будет просто

    return type.getAnnotation(MyPlain.class) != null;
    

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

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

Классы, на которых будет работать процессор

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

Если SupportedAnnotationTypes равно "*", то процессор будет вызываться для всех классов, аннотированных или нет! Проверьте [Javadoc] (http://java.sun.com/javase/6/docs/api/javax/annotation/processing/Processor.html#getSupportedAnnotationTypes()),, который гласит:

Наконец, "*" само по себе представляет набор всех типов аннотаций, в том числе пустой набор. Обратите внимание, что процессор не должен требовать "*", если это не фактически обрабатывает все файлы; требовать ненужные аннотации могут вызвать снижение производительности в некоторых окружающая среда. * * тысяча шестьдесят-шесть

Обратите внимание, как возвращается false, чтобы процессор не запрашивал все аннотации.

6 голосов
/ 19 ноября 2009

Нет. Вышеуказанный чек может быть легче переписан как:

try {
  MyClass.newInstance();
} catch (InstantiationException E) {
  // no constructor
} catch (IllegalAccessException E) {
  // constructor exists but is not accessible
?
1 голос
/ 08 мая 2010

Вы можете использовать PMD и Macker, чтобы гарантировать архитектурные правила. В частности, Macker провоцирует ошибки компиляции, нарушая процесс сборки при сбое проверки.

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

Итак, если вы очень параноидальны (как и я!) В отношении проверки всех возможных архитектурных правил, Macker действительно полезен.

http://innig.net/macker/

Примечание: сайт не великолепен. Цвета повредят глаза ... но инструменты все равно очень полезны.

Ричард Гомес http://www.jquantlib.org/

...