Атрибут Annotation должен быть литералом класса? Зачем? Константы тоже должны быть хорошими

Может кто-нибудь объяснить, почему параметры аннотации String и Class ожидаются по-разному? Почему компилятор требует литералов для классов, если также принимать константы для строк?

Рабочий пример с Spring @RequestMapping:

public class MyController {
    public static final String REQUEST_MAPPING = "/index.html";
    @RequestMapping(MyController.REQUEST_MAPPING) // ALL OK!
    ...
}

Пример WTF с TestNG @Test:

public class MyControllerTest {
    public static final Class TEST_EXCEPTION = RuntimeException.class;
    @Test(expectedExceptions = MyControllerTest.TEST_EXCEPTION) // compilation error, WTF:
    // The value for annotation attribute Test.expectedExceptions must be a class literal
    ...
}

Что, конечно же, работает @Test (expectedExceptions = RuntimeException.class). Но почему? Единственное отличие в параметре аннотации, которое я вижу, это его тип: String vs Class. Почему бы компилятор Java не принимал константу String, но принимал только литералы класса?

Ответ 1

Спецификация языка Java не позволяет использовать константы времени компиляции с параметрами типа Class. Вы можете использовать только литералы класса.

JLS имеет следующие значения подходящих значений параметров для аннотаций:

Тип элемента T соизмерим с значением элемента V тогда и только тогда, когда выполняется одно из следующих условий:

  • T - тип массива E [] и либо:
    • V является ElementValueArrayInitializer, и каждый ElementValueInitializer (аналогичный инициализатору переменной в инициализаторе массива) в V соизмерим с E. Or
    • V - элемент ElementValue, соизмеримый с T.
  • Тип V является совместимым присваиванием (§5.2) с T и, кроме того:
    • Если T является примитивным типом или строкой, V является константным выражением (§15.28).
    • V не является нулевым.
    • , если T является классом или вызовом класса, а V является литералом класса (§15.8.2).
    • Если T - тип перечисления, а V - константа перечисления.

Это ошибка времени компиляции, если тип элемента не соразмерен с ElementValue.

Я не могу сказать, почему это ограничение находится в JLS.

Ответ 2

Я получил значение аннотации, которое должно быть литералом класса:

@ServerEndpoint(value="/story/notifications",
        encoders = (StickerEncoder.class),
        decoders = (StickerDecoder.class))

Это происходит, следуя одному из уроков Оракула на веб-сайтах. Оказывается, видео не является качеством 720p, а нечеткость скрывает фигурные скобки, которые выглядят как фигурные скобки. Таким образом, ошибка исчезает при изменении скобок (скобок) для фигурных скобок.

@ServerEndpoint(value="/story/notifications",
        encoders = {StickerEncoder.class},
        decoders = {StickerDecoder.class})

hth любой, кто может путешествовать по тому же в будущем.

Ответ 3

Посмотрите:

public static final Class TEST_EXCEPTION = RuntimeException.class;

Класс должен быть Throwable, который компилятор может проверить. Итак, попробуйте следующее:

public static final Class<? extends Throwable> TEST_EXCEPTION = RuntimeException.class;

Ответ 4

Комната не имеет встроенной поддержки для хранения дат, вам нужно преобразовать ее в значения LONG при вставке и чтении в базу данных и из нее. Следовательно, мы несем ответственность за указание базы данных Room, как конвертировать данные

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

Например, при работе с датами:

import android.arch.persistence.room.TypeConverter;
import java.util.Date;

//Type-Converter Class for Room
public class DateConverter {
    @TypeConverter
    // Long value to Date value
    public static Date toDate(Long timestamp) {
        return timestamp == null ? null : new Date(timestamp);
    }

    @TypeConverter
    // Date value to Long value
    public static Long toTimestamp(Date date) {
        return date == null ? null : date.getTime();
    }
}

Теперь мы должны указать нашему классу базы данных использовать этот класс TypeConverter, используя @TypeConverters (убедитесь, что используется множественная версия).

@Database(entities = {Entity.class}, version = 1)
@TypeConverters(DateConverter.class)
public abstract class AppDatabase extends RoomDatabase {...}    

Вы готовы к рок!

Ответ 5

    maven {
        url 'https://maven.google.com'
    }

Вы должны вставить это в свой проект build.gradle(Project: MyApplication (Project Name))

implementation 'android.arch.persistence.room:runtime:1.1.1'
annotationProcessor 'android.arch.persistence.room:compiler:1.1.1'

Вы должны вставить это в свой проект build.gradle (Модуль: приложение)

Могут быть проблемы с зависимостями или просто с их именами.

Если вы хотите полный пример кода, перейдите по ссылке:

https://www.captechconsulting.com/blogs/android-architecture-components-room-persistence-library