Resource annotations and @IntDef and @StringDef

Are there any plans to introduce support for integer annotations for resources in Android, such as @StringRes , @ColorRes , @LayoutRes , along with the lint checks around them.

Also, it would be nice if we could get support for @IntDef and @StringDef . I’m sure that every Android programmer has learned to appreciate them.

I also hoping that they would be supported with the changes that came in 1.0.2 regarding Android annotations. I suppose this is coming later? Or are the support annotations not yet on the list?

Kotlin 1.0.2 includes Android Lint diagnostics, so @ColorRes , @LayoutRes and other annotations are supported now. Note that Lint diagnostics are in beta, so please create an issue if something does not work as expected.

How does one enable this functionality, because I could not see it for my code.

With either 1.1 or 1.1.1 I started getting bogus lint underlines on @IntegerRes

both the @IntegerRes are linted. Is this because the IDE just started considering them in 1.1? I think the linting is wrong… The lint error is “This annotation does not apply for type void”

Related Topics

kotlin resource annotation

How Kotlin Annotations Work — Part 1

Sherry Yuan

Sherry Yuan

ProAndroidDev

Android developers can build complex apps with annotations scattered throughout, such as @Provides from Dagger or @ColorRes from AndroidX , without fully understanding how they work; they can almost feel like magic. This article will unshroud some of the magic by exploring the three main mechanisms that handle annotations: annotation processing , reflection , and lint .

In How Kotlin Annotations Work — Part 2 , I’ll provide a case study on how a real-world annotation-based library, Moshi , uses all three mechanisms.

What are Kotlin annotations?

Annotations are a means of attaching metadata to code . To declare an annotation, put the annotation modifier in front of a class:

We can annotate it with meta-annotations to provide additional details:

@Target specifies the possible kinds of elements which can be annotated with the annotation (such as classes, functions, parameters), and @Retention specifies whether the annotation is stored in binary output and whether it’s visible for reflection at runtime. In its default value RUNTIME , both are true.

Annotation processing and reflection fall into the category of metaprogramming , a technique in which programs use other programs (eg. Kotlin source code) as their data. Both mechanisms leverage annotations to reduce boilerplate code and automate common tasks. For example, most dependency injection (eg. Dagger) and serialization (eg. Moshi ) libraries use one or the other, or both. Annotation processing and reflection can achieve similar behavior — Moshi supports both mechanisms for generating JSON adapters. Lint is a different use case, using annotations to check source files for issues. Whether it counts as metaprogramming is hazy.

All three mechanisms offer powerful and flexible APIs, so different annotations can achieve very different effects depending on how they’re handled in code. Developers rarely have to write this code ourselves, because we use annotations from libraries that already handle them more often than we create our own annotations.

Annotation Processing

Annotation processors are compiler plugins that generate code based on annotations at compile time. You know a third-party library includes an annotation processor when it requires using annotationProcessor , kapt or ksp instead of implementation as its build.gradle dependency configuration . Popular libraries that rely on annotation processing include Dagger ( @Provides , @Inject ), Moshi ( @Json ), and Room ( @Entity , @Dao ).

An annotation processor must be registered to the compiler for it to run during compilation. The most common way to register one is via Google’s AutoService library — just annotate your processor with @AutoService(Processor.class) .

There are three main APIs for creating annotation processors: Annotation Processor Tool (APT), Kotlin Annotation Processor Tool (kapt), and Kotlin Symbol Processing (KSP). Processors created with APT and kapt extend the same base AbstractProcessor class, whereas KSP has a separate SymbolProcessor class.

Annotation processing takes multiple rounds. In each round, the compiler searches for annotations in the generated source files and calls their corresponding processors. If the processors generate any new files, a new round starts with the generated files as input. The process continues until no new files are generated.

Annotation Processor Tool

APT is the only API from the pre-Kotlin Android world. It’s used by the Java compiler (javac) and corresponds to the annotationProcessor dependency configuration. It’s rarely seen in Android projects nowadays because it doesn’t support Kotlin files.

APT annotation processors work with .java source code files. To create one, we need to make a class that extends AbstractProcessor . The two main functions to implement are getSupportedAnnotationTypes() , which should return which annotations it can process, and process() , which is the main block getting called on every processing round. Here, we have to think about source code as structured text instead of something executable — similar to a JSON file. The source code is represented as a tree of Element s, which represents program elements including packages, classes, or functions.

AbstractProcessor.process() ’s second parameter is roundEnv , a RoundEnvironment object with information about the current and prior processing rounds. It provides access to the tree of Element s and several ways to examine annotations associated with the Elements , for example getElementsAnnotatedWith() .

We can generate code based on annotated Element s in process() . The Filer from the processor’s ProcessingEnvironment lets us create new files, then write to them like any other file. Generated files will appear under the project’s <module>/build/generated/source/ directory. This is how Dagger generates its Something_Factory and Something_MembersInjector classes, and Moshi its SomethingAdapter classes. JavaPoet is a popular library for writing Java source code.

I won’t go over implementing a custom AbstractProcessor because there are plenty of resources on it already, which I’ll link to at the end of this article. In my next article, I’ll explore how Moshi’s JsonClassCodegenProcessor implements it.

Kotlin Annotation Processor Tool

Kapt became the go-to annotation processor API once Kotlin gained popularity. It’s a compiler plugin built on top of APT and supports both Kotlin and Java source code. It corresponds to the kapt dependency configuration. It uses the same AbstractProcessor as APT, so the previous section’s information about creating APT annotation processors also applies to kapt. Kapt can run any AbstractProcessor regardless if it was written with Kotlin or Java support in mind. KotlinPoet is a popular library for generating Kotlin source code during processing.

Kapt’s main downside is its slow compilation time. It runs on javac like APT, and works with Kotlin by generating Java stubs from Kotlin files that the processors can then read. This stub generation is an expensive operation and has a significant impact on build speed.

Kotlin Symbol Processing

KSP is a Kotlin-first alternative to kapt introduced in 2021. With direct integration into the Kotlin compiler (kotlinc), KSP analyzes Kotlin code directly without generating Java stubs and is up to 2x faster than kapt. It also has a better understanding of Kotlin’s language constructs.

If a module has any kapt processors remaining, it’ll still generate Java stubs during compilation. This means we only get KSP’s performance improvements if all usages of kapt are removed from the module.

To create a KSP annotation processor, we need to implement SymbolProcessor . KSP also represents source code as a syntax tree and provides a similar API to Kapt . A KsDeclaration or KsDeclarationContainer in KSP maps to an Element in Kapt. The Resolver , like Kapt’s RoundEnvironment , is the parameter in SymbolProcessor.process() providing access to the syntax tree. Resolver.getSymbolsWithAnnotation() lets us examine symbols with custom annotations that we’re interested in. Finally, like Filer , SymbolProcessorEnvironment ’s CodeGenerator lets us generate code while processing.

Reflection is defined as a language’s ability to inspect its classes, interfaces, fields, and methods at runtime without knowing their names at compile time. It lets programs dynamically instantiate new objects and invoke methods — ie. modify their structure and behavior at runtime. Popular libraries that use reflection to modify program behavior include Moshi ( @Json ) and Retrofit ( @GET , @POST ).

The standard Java reflection library works in Kotlin. Kotlin also has its own reflection API, available through the kotlin-reflect package, which provides a few additional features, including access to properties and nullable types.

Here’s an example of invoking a method at runtime via reflection:

Reflection doesn’t always involve annotations, but it provides a robust API for working with them and annotations can make its usage safer and more powerful.

For example, we can update the previous code to invoke all methods annotated with @Greeter without specifying their names in hard-coded strings:

Other annotation-related functions available in Kotlin’s reflection API include KAnnotatedElement.findAnnotations() and KAnnotatedElement.hasAnnotation() . For an annotation to work with reflection, its @Retention policy needs to be RUNTIME (the default retention).

When deciding between handling annotations via reflection or annotation processing, the main trade offs are:

  • Reflection means slower runtime vs annotation processing means slower compile time
  • Reflection fails at runtime vs annotation processing fails at compile time

Most libraries prefer annotation processing, because its slower compile time won’t impact the end user experience and its compile time errors fail fast, whereas reflection’s runtime errors are more likely to go unnoticed until they reach end users. Dagger completely got rid of reflection when migrating from v1 to v2 for these reasons.

Retrofit, a popular HTTP client library, still relies entirely on reflection. It uses Proxy to generate instances of annotated interfaces. Reflection makes sense here because the latency of a network request far outweighs any latency introduced by reflection, and runtime failures are relatively easy to identify; we can test new Retrofit code by triggering its corresponding API call.

Lint is a code scanning tool that checks your Android project source files for potential bugs and improvements ranging from security, performance, accessibility, internationalization, and more. For the sake of brevity, I’m only discussing the first-party lint tool and won’t cover any third-party tools like Detekt .

Lint is deeply integrated into Android Studio, and highlights issues as warnings or errors in the IDE.

Many lint checks, including the “Unnecessary safe call” above, don’t involve annotations. However, annotations can help lint detect more subtle code problems. Since Java doesn’t have built-in nullability like Kotlin, @Nonnull and @Nullable let lint provide the same null-safety warnings for Kotlin. Another example is @ColorRes , which lets lint know that an Int parameter should be a color resource reference (e.g. android.R.color.black ).

Unlike annotation processing and reflection, Lint only performs static code analysis and can’t affect program behavior. And unlike the other two where annotations usually come from third-party libraries, most commonly-used lint-related annotations are from the androidx.annotations package and handled by Android Studio’s built-in checks.

When we do want to add a custom lint check — either our own or from a third-party library -, we’ll have to use the lintChecks or lintPublish dependency configuration. lintChecks makes the lint rule available only for that module, whereas lintPublish makes it available to all upstream modules.

To add a new lint check, we have to create a subclass of Detector . Detectors can run on different file types depending on which FileScanner it implements. For example, SourceCodeScanner can analyze Kotlin or Java source files and GradleScanner can analyze Gradle files.

SourceCodeScanner is the relevant scanner for handling annotations. It offers two Abstract Syntax Tree (AST) APIs, developed by Jetbrains, for analyzing source code. The Universal Abstract Syntax Tree (UAST) API represents multiple languages the same way, making it possible to write a single analyzer which works “universally” across all languages supported by UAST, including Kotlin and Java.

Before UAST, there was Program Structure Interface (PSI). PSI represents Kotlin and Java differently and is sometimes still needed for language-specific nuances. UAST is built on top of PSI, so its API occasionally leaks PSI elements. Navigating the ASTs looks similar to navigating the Element s trees from annotation processing.

Google’s custom lint rules guide has a helpful page on how to add a lint check that visits annotated elements. If we want to visit usages of a custom annotation directly rather than only the elements annotated with it, we can override SourceCodeScanner ’s getApplicatbleUastTypes() to return UAnnotation::class.java , then override createUastHandler() to return a custom UElementHandler . Any issue detection related to our custom annotation can go in the UElementHandler ’s visitAnnotation() .

Mysterious custom annotations

Sometimes, you’ll encounter a custom annotation in a codebase that isn’t referenced in any custom annotation processors, reflection code, or lint checks, so what’s it doing?

It’s most likely annotated with a meta-annotation from a third-party library; several popular ones provide functionality that relies on meta-annotations. For example, Dagger has a @Qualifier meta-annotation for cases where the type alone is insufficient to identify a dependency.

@Qualifier lets us create custom annotations like this:

We could use them to inject different instances of a class depending on whether the user is signed in.

You don’t need to write any code to handle these custom annotations; Dagger’s annotation processor will search for all @Qualifier custom annotations and process them for you. Moshi has a similar @JsonQualifier meta-annotation for specifying how a type is encoded for some fields without changing its encoding everywhere.

Additional resources

  • How Kotlin Annotations Work — Part 2: Moshi Case Study
  • Annotation Processing Boilerplate Destruction talk
  • Writing your own Annotation Processors in Android article
  • Baeldung’s Kotlin Annotations article
  • Android custom lint rules guide

As always, thanks for reading! And shoutout to Russell and Kelvin for their valuable editing and feedback 🖤

Sherry Yuan

Written by Sherry Yuan

Android engineer @ Cash App (she/her)

More from Sherry Yuan and ProAndroidDev

Collapsing Toolbar in Jetpack Compose LazyColumn — 3 Approaches

Collapsing Toolbar in Jetpack Compose LazyColumn — 3 Approaches

Exploring scaffold, box, and largetopappbar.

Protect your code from Gemini in Android Studio

Katie Barnett

Protect your code from Gemini in Android Studio

The studio bot is great, but be sure you are not sharing proprietary code unintentionally.

App Architecture: Domain layer

Mkhytar Mkhoian

App Architecture: Domain layer

The domain layer is a layer that sits between the ui layer and the data layer. it should be the most stable layer in the app..

Android Touch System — Part 4: Gesture-Handling Modifiers in Jetpack Compose

Android Touch System — Part 4: Gesture-Handling Modifiers in Jetpack Compose

Exploring gesture-related modifiers in jeptack compose and how to use them., recommended from medium.

Kotlin 2.0.0 migration guide as an Android developer

Jonathan Mercandalli

Kotlin 2.0.0 migration guide as an Android developer

How to bump kotlin from 1.9.24 to 2.0.0 and gain 9% of compile time..

Kotlin Design Patterns: Flyweight

Michal Ankiersztajn

Kotlin Design Patterns: Flyweight

Flyweight is a structural design pattern used to limit memory allocation inside your app using a caching mechanism.

kotlin resource annotation

General Coding Knowledge

kotlin resource annotation

Stories to Help You Grow as a Software Developer

An illustration of two women standing in front of a climbing wall, having a discussion about the climb they are about to do.

Good Product Thinking

“if vs let” in Kotlin

Khush Panchal

“if vs let” in Kotlin

Should i use “if” or “let” for nullable type objects in kotlin.

Mastering Synchronization in Kotlin: Best Practices for Multithreaded Programming

Rizwanul Haque

Stackademic

Mastering Synchronization in Kotlin: Best Practices for Multithreaded Programming

Multithreaded programming in kotlin offers tremendous potential for building responsive and efficient applications. however, with the power….

MVI at Eventbrite

Karishma Agrawal

Level Up Coding

MVI at Eventbrite

6 months ago i joined eventbrite as senior android engineer. after working for 6 months here, one thing that i found is, this is just not a….

Now in Android #106

Android Developers

Now in Android #106

I/o’24, android 15, kmp, compose, androidx, and more.

Text to speech

Press ESC to close

a guy looking at the screen trying to understand kotlin annotations.

A Comprehensive Guide to Understanding Kotlin Annotations

Annotations are an essential part of the Kotlin language, providing a way to add metadata to classes, methods, properties, and others. Mastering the details of annotations is critical to unlocking the full potential of Kotlin, making it easier to document and write more efficient and readable code.

In this blog post, we will dive deep to understand how annotations work in Kotlin.

Why Annotations?

Kotlin annotations are used to attach metadata to code. This allows the compiler or the reflection API to access this metadata for various purposes. For example, the compiler can use annotations to check for errors in the code, generate code, or to analyze code.

Creating a custom annotation

That’s all you need to define a custom annotation you can apply on any element.

Here is what the decompiled Kotlin bytecode looks like:

Yes! Annotation types are a form of interface .

Let’s dive into the details…

We can annotate this annotation class 😁 Yes!

Annotation: @Retention

We use the retention annotation to specify whether the annotation will be available for source-processing tools, at runtime, or in the compiled class files. But what is the difference?

SOURCE Retention annotations are unavailable for the reflection API and the compiled class files. They are used to provide information to the source-processing tools . To better understand, let’s look at the “Suppress” annotation from the Kotlin Standard Library:

We all used it before to suppress compilation warnings by the compiler. It is discarded during the runtime and will not be present in the compiled class files.

Let’s use the suppress annotation:

The decompiled Kotlin bytecode will not contain any reference to “suppress”

⇒ RUNTIME (Default)

RUNTIME annotations are available for the reflection API and get discarded during compilation. They are also available in the compiled class files .

Let’s see an example when declaring a qualifier for Dagger

Similar to RetentionPolicy.CLASS in Java, BINARY annotations are only available in the compiled class files. They are used only when an annotation must be present in the compiled files and irrelevant for runtime.

For example, the ProGuard tool operates on “.jar” files, so annotations like @Keep and @KeepClassMembers need to be present but irrelevant at the runtime.

Annotation: @Target

The @Target annotation in Kotlin allows developers to specify the types of elements that can be annotated. This includes classes, methods, properties, and others. With this annotation, developers can assign specific annotations to the elements that meet their requirements.

@Target can accept many targets simultaneously or none if nothing was passed as an argument.

Here are all the possible values:

Annotation: @Repeatable

Kotlin makes it possible to apply the same annotation to one element multiple times by using the @Repeatable annotation.

Let’s look at the example below

Annotation: @MustBeDocumented

@MustBeDocumented indicates that the element is part of the public API, and its documentation must be generated. By utilizing this annotation, developers can ensure that all public API elements are accurately and adequately documented.

Annotations Constructor

Kotlin annotations can have a constructor which requires parameters. These parameters can take the following types:

  • Java primitive types
  • Annotation classes
  • Arrays of all the types above

Kotlin enables developers to conveniently invoke the constructor of an annotation class as they would with any regular class, providing a great deal of flexibility.

Use-Site Targets

If you have ever looked at a decompiled Kotlin bytecode, you will notice that multiple java elements are generated for the corresponding Kotlin element.

We need a way to specify which Java elements are affected by the annotation.

Kotlin’s annotation use-site targets provide a way to customize the effects of an annotation when applied to a certain element. These targets let developers customize how the annotation is interpreted and how it affects the code.

Here is what the decompiled bytecode looks like:

Here is the list of all the targets you can use:

The @file target can be used to add annotations to any Kotlin file in a project.

The decompiled bytecode looks something like this:

@get and @set

Explained above 👆

@param annotations could be applied only to primary constructor parameters.

@receiver annotates the receiver parameter of an extension function or property.

@setparam annotates the property setter parameter.

To understand @delegate target, let’s look at the example below:

If you take look at the decompiled bytecode, the annotation will be placed on the generated private backing property, whose type will be the type of the delegate.

Java Interoperability

Kotlin is designed with Java interoperability in mind, including annotations.

Here are some rules you need to stick to:

  • If you use a Java annotation with multiple parameters, use the named argument syntax in Kotlin.
  • If the Java annotation has the value parameter, you need to specify it in Kotlin.
  • If the value parameter is an array type, it becomes a vararg parameter in Kotlin.
  • For any other array parameter, it becomes an array in Kotlin.

Now that you know all about Kotlin annotations and how they work, you can start writing even more powerful applications.

If you want to dive deeper into the subject, I would recommend taking a look at the following articles:

  • Annotation Processing: Supercharge Your Development
  • Advanced Annotation Processing
  • KSP: Fact o r kapt?

These resources will guide you in building an annotation processor step-by-step.

I hope this post has been useful and informative. Please share it with your friends and colleagues if you find it helpful. Thank you!

Share Article:

I'm a Software Engineer with a focus on Android development. With over 6 years of experience in coding and new technologies, I'm passionate about creating solutions that make life easier. I'm constantly exploring new opportunities to expand my knowledge and I'm always happy to share my insights with others.

Navigating the Android Jungle: Top Resources and Creators to Follow 2023

Leave a reply cancel reply.

Save my name, email, and website in this browser for the next time I comment.

Collections

  • Android Studio
  • Kotlin Android
  • Android Projects
  • Android Interview Questions
  • Kotlin Tutorial
  • Introduction to Kotlin
  • Kotlin Environment setup for Command Line
  • Kotlin Environment setup with Intellij IDEA
  • Hello World program in Kotlin
  • Kotlin Data Types
  • Kotlin Variables
  • Kotlin Operators
  • Kotlin Standard Input/Output
  • Kotlin Type Conversion
  • Kotlin Expression, Statement and Block

Control Flow

  • Kotlin if-else expression
  • Kotlin while loop
  • Kotlin do-while loop
  • Kotlin for loop
  • Kotlin when expression
  • Kotlin Unlabelled break
  • Kotlin labelled continue

Array & String

  • Kotlin Array
  • Kotlin String
  • Kotlin functions
  • Kotlin | Default and Named argument
  • Kotlin Recursion
  • Kotlin Tail Recursion
  • Kotlin | Lambdas Expressions and Anonymous Functions
  • Kotlin Inline Functions
  • Kotlin infix function notation
  • Kotlin Higher-Order Functions
  • Kotlin Collections
  • Kotlin list : Arraylist
  • Kotlin list : listOf()
  • Kotlin Set : setOf()
  • Kotlin hashSetOf()
  • Kotlin Map : mapOf()
  • Kotlin Hashmap

OOPs Concept

  • Kotlin Class and Objects
  • Kotlin Nested class and Inner class
  • Kotlin Setters and Getters
  • Kotlin | Class Properties and Custom Accessors
  • Kotlin Constructor
  • Kotlin Visibility Modifiers
  • Kotlin Inheritance
  • Kotlin Interfaces
  • Kotlin Data Classes
  • Kotlin Sealed Classes
  • Kotlin Abstract class
  • Enum Classes in Kotlin
  • Kotlin extension function
  • Kotlin generics

Exception Handling

  • Kotlin Exception Handling | try, catch, throw and finally
  • Kotlin Nested try block and multiple catch block

Null Safety

  • Kotlin Null Safety
  • Kotlin | Type Checking and Smart Casting
  • Kotlin | Explicit type casting

Regex & Ranges

  • Kotlin Regular Expression
  • Kotlin Ranges

Java Interoperability

  • Java Interoperability - Calling Kotlin from Java
  • Java Interoperability - Calling Java from Kotlin

Miscellaneous

Kotlin annotations.

  • Kotlin Reflection
  • Kotlin Operator Overloading
  • Destructuring Declarations in Kotlin
  • Equality evaluation in Kotlin
  • Comparator in Kotlin
  • Triple in Kotlin
  • Pair in Kotlin
  • Kotlin | apply vs with
  • Kotlin Android Tutorial
  • How to create project in Android Studio using Kotlin
  • How to Install Android Virtual Device(AVD)?
  • Android Animations in Kotlin
  • Android Fade In/Out in Kotlin
  • Android Menus
  • Android progress notifications in Kotlin
  • Android Project folder Structure

Annotations are a feature of Kotlin that allows the programmer to embed supplemental information into the source file. This information, however, does not changes the actions of the program. This information is used by various tools during both development and deployment. Annotations contains the following parameters most frequently and these must be compile-time constants:   

  • primitive types(Int,Long etc)
  • enumerations
  • other annotations
  • arrays of the above-mentioned types

Applying Annotation –

We can apply annotation by putting its name prefixed with the @ symbol in front of a code element. For example, if we want to apply an annotation named Positive, we should write the following if we want to write annotation Pos  

A parameter can be passed in parenthesis to an annotation similar to function call.   

When an annotation is passed as parameter in another annotation, then we should omit the @ symbol. Here we have passed Replacewith() annotation as parameter.   

When an annotation parameter is a class object, we should add ::class to the class name as:   

Declaring Annotation –

To declare an annotation, the class keyword is prefixed with the annotation keyword. By their nature, declarations of annotation cannot contain any code. While declaring our custom annotations, we should specify to which code elements they might apply and where they should be stored.  The simplest annotation contains no parameters –   

An annotation that requires parameter is much similar to a class with a primary constructor –   

Annotate a constructor –

We can also annotate the constructor of a class. It can be done by using the constructor keyword for constructor declaration and placing the annotation before it.   

Annotate a property –

We can annotate the properties of class by adding an annotation to the properties. In below example, we assume that an Lang instance is valid if the value of the name is either Kotlin or Java.   

Some in-built annotations –

Kotlin also provides certain in-built annotations, that are used to provide more attributes to user-defined annotations. To be precise, these annotations are used to annotate annotations.  @Target –   This annotation specifies the places where the annotated annotation can be applied such as classes, functions, constructors, type parameters, etc. When an annotation is applied to the primary constructor for a class, the constructor keyword is specified before the constructor.  Example to demonstrate @Target annotation    

Output:    

@Retention –   This annotation specifies the availability of the annotated annotation i.e whether the annotation remains in the source file, or it is available at runtime, etc. Its required parameter must be an instance of the AnnotationRetention enumeration that has the following elements:   

Example to demonstrate @Retention annotation:    

@Repeatable –   This annotation allows an element to be annotated with the same annotation multiple times. As per the current version of Kotlin 1.3, this annotation can only be used with the Retention Policy set to SOURCE.  Example to demonstrate @Repeatable    

Please Login to comment...

Similar reads, improve your coding skills with practice.

 alt=

What kind of Experience do you want to share?

Kotlin - Annotations

This tutorial lets you write a Kotlin application and use Koin dependency injection to retrieve your components. You need around 10 min to do the tutorial.

Get the code ​

The source code is available at on Github

Let's configure the KSP plugin like below in Gradle:

Let's setup the dependencies like below:

Application Overview ​

The idea of the application is to manage a list of users, and display it in our UserApplication class:

Users -> UserRepository -> UserService -> UserApplication

The "User" Data ​

We will manage a collection of Users. Here is the data class:

We create a "Repository" component to manage the list of users (add users or find one by name). Here below, the UserRepository interface and its implementation:

The Koin module ​

Let's declare a AppModule module class like below.

  • We use the @Module to declare our class as Koin module
  • The @ComponentScan("org.koin.sample") allow to scann any Koin definition in "org.koin.sample" package

Let's simply add @Single on UserRepositoryImpl class to declare it as singleton:

The UserService Component ​

Let's write the UserService component to request the default user:

UserRepository is referenced in UserPresenter`s constructor

Let's simply add @Single on UserService class to declare it as singleton:

Injecting Dependencies in UserApplication ​

The UserApplication class will help bootstrap instances out of Koin. It will resolve the UserService , thanks to KoinComponent interface. This allows to inject it with the by inject() delegate function:

That's it, your app is ready.

The by inject() function allows us to retrieve Koin instances, in any class that extends KoinComponent

Start Koin ​

We need to start Koin with our application. Just call the startKoin() function in the application's main entry point, our main function:

The Koin module is generated from AppModule with the .module extension: Just use the AppModule().module expression to get the Koin module from the annotations.

The import org.koin.ksp.generated.* import is required to allow to use generated Koin module content

Compile Time Checks ​

Koin Annotations allows to check your Koin configuration at compile time. This is available by jusing the following Gradle option:

  • Get the code
  • Application Overview
  • The "User" Data
  • The Koin module
  • The UserService Component
  • Injecting Dependencies in UserApplication
  • Compile Time Checks

DB-City

  • Bahasa Indonesia
  • Eastern Europe
  • Moscow Oblast

Elektrostal

Elektrostal Localisation : Country Russia , Oblast Moscow Oblast . Available Information : Geographical coordinates , Population, Altitude, Area, Weather and Hotel . Nearby cities and villages : Noginsk , Pavlovsky Posad and Staraya Kupavna .

Information

Find all the information of Elektrostal or click on the section of your choice in the left menu.

  • Update data

Elektrostal Demography

Information on the people and the population of Elektrostal.

Elektrostal Geography

Geographic Information regarding City of Elektrostal .

Elektrostal Distance

Distance (in kilometers) between Elektrostal and the biggest cities of Russia.

Elektrostal Map

Locate simply the city of Elektrostal through the card, map and satellite image of the city.

Elektrostal Nearby cities and villages

Elektrostal weather.

Weather forecast for the next coming days and current time of Elektrostal.

Elektrostal Sunrise and sunset

Find below the times of sunrise and sunset calculated 7 days to Elektrostal.

Elektrostal Hotel

Our team has selected for you a list of hotel in Elektrostal classified by value for money. Book your hotel room at the best price.

Elektrostal Nearby

Below is a list of activities and point of interest in Elektrostal and its surroundings.

Elektrostal Page

Russia Flag

  • Information /Russian-Federation--Moscow-Oblast--Elektrostal#info
  • Demography /Russian-Federation--Moscow-Oblast--Elektrostal#demo
  • Geography /Russian-Federation--Moscow-Oblast--Elektrostal#geo
  • Distance /Russian-Federation--Moscow-Oblast--Elektrostal#dist1
  • Map /Russian-Federation--Moscow-Oblast--Elektrostal#map
  • Nearby cities and villages /Russian-Federation--Moscow-Oblast--Elektrostal#dist2
  • Weather /Russian-Federation--Moscow-Oblast--Elektrostal#weather
  • Sunrise and sunset /Russian-Federation--Moscow-Oblast--Elektrostal#sun
  • Hotel /Russian-Federation--Moscow-Oblast--Elektrostal#hotel
  • Nearby /Russian-Federation--Moscow-Oblast--Elektrostal#around
  • Page /Russian-Federation--Moscow-Oblast--Elektrostal#page
  • Terms of Use
  • Copyright © 2024 DB-City - All rights reserved
  • Change Ad Consent Do not sell my data

Help | Advanced Search

Computer Science > Computer Vision and Pattern Recognition

Title: hi5: 2d hand pose estimation with zero human annotation.

Abstract: We propose a new large synthetic hand pose estimation dataset, Hi5, and a novel inexpensive method for collecting high-quality synthetic data that requires no human annotation or validation. Leveraging recent advancements in computer graphics, high-fidelity 3D hand models with diverse genders and skin colors, and dynamic environments and camera movements, our data synthesis pipeline allows precise control over data diversity and representation, ensuring robust and fair model training. We generate a dataset with 583,000 images with accurate pose annotation using a single consumer PC that closely represents real-world variability. Pose estimation models trained with Hi5 perform competitively on real-hand benchmarks while surpassing models trained with real data when tested on occlusions and perturbations. Our experiments show promising results for synthetic data as a viable solution for data representation problems in real datasets. Overall, this paper provides a promising new approach to synthetic data creation and annotation that can reduce costs and increase the diversity and quality of data for hand pose estimation.

Submission history

Access paper:.

  • HTML (experimental)
  • Other Formats

license icon

References & Citations

  • Google Scholar
  • Semantic Scholar

BibTeX formatted citation

BibSonomy logo

Bibliographic and Citation Tools

Code, data and media associated with this article, recommenders and search tools.

  • Institution

arXivLabs: experimental projects with community collaborators

arXivLabs is a framework that allows collaborators to develop and share new arXiv features directly on our website.

Both individuals and organizations that work with arXivLabs have embraced and accepted our values of openness, community, excellence, and user data privacy. arXiv is committed to these values and only works with partners that adhere to them.

Have an idea for a project that will add value for arXiv's community? Learn more about arXivLabs .

The code quality platform for teams

  • Twitter Twitter

Static Code Analysis for Spring: Run Analysis, Fix Critical Errors, Hit the Beach

Anton Arhipov

Fun fact: 72% of our JVM users use Spring in their applications, especially in industries like manufacturing and finance. Why? Spring makes programming with Java and Kotlin quicker, easier, and safer for everybody – but it also comes with unique challenges.

Why is it so tricky to manage code quality in Spring?

Spring has a rich API interface with annotations and configuration files – a broad system with many specifics. It’s a framework that works like glue for your app, determining how you structure, build, and run code, freeing you up to think about which logic to apply. 

In a Spring Framework project, you can change one file, and everything will still look correct. However, this small change can easily affect your app’s configuration and lead to errors in other files. It’s possible that you won’t see these errors until you open those other files, which is too late. 

To confidently change files in such a project, you need safeguards to help you navigate code quality in such a complex framework. That’s why we originally built the Spring plugin for IntelliJ IDEA to include a wide range of Spring-specific inspections for everyday use.  Now, we’ve added Spring-specific inspections to Qodana.

Spring, Qodana, and IntelliJ IDEA: How do the three work together?

The out-of-the-box experience of IntelliJ IDEA gives you everything you need for typical Java and Kotlin development, including Spring. The plugin contributes various checks for Spring Framework and comes bundled with the Qodana JVM linter.

You can find the full list of inspections for Spring Framework in IntelliJ IDEA under Settings | Editor | Inspections by searching for “Spring” to filter out irrelevant inspections.

Qodana for spring framework

The same checks run in the IDE when you write code and even include server-side analysis. This means that if you missed some issue in the IDE, it will be detected by the Qodana linter in the CI pipeline.

The Qodana report will reveal the issues that snuck into the project, and everyone on the team will know. Qodana makes code reviews a team sport ahead of runtime, improving overall code quality and bringing enhanced collaboration to your team’s workflow.

Qodana code reviews, Spring code reviews

Spring inspection groups

Spring inspections can be grouped by use case into checks for issues related to autowiring, configuration files, the data access layer, the web layer, and many more. Let’s take a closer look at some of these groups. 

Spring autowiring inspections

As Spring’s programming model relies on annotations, the various components are typically scattered across the project and often reside in different files and packages. It’s not immediately obvious whether the required dependencies exist, whether there are no conflicts, or whether the references to lifecycle methods are correct. These problems fall into the category of autowiring issues, and this is the most typical group of issues that developers face when working with the Spring Framework.

You can spot many autowiring issues in Spring’s context in the editor, highlighted as you type. These include minor recommendations, such as avoiding field injection, or bigger issues, such as a mistyped package name in the ComponentScan annotation.

Let’s look at an example of a situation in which changing one component in a Spring application may cause the failure of another component. In Spring applications, it’s possible to describe a dependency between components using the @DependsOn annotation, where a dependency name is specified as a string. The components might reside in different parts of the project, and a change in the dependency could potentially break the lifecycle of a dependent component.

Spring dependancies Qodana

In the screenshot above, the IDE reports that the dependency referenced in the @DependsOn annotation parameter cannot be resolved, even though the GeneralConfig class that implements the component is visible in the project tree.

The problem is a typo in the reference name: instead of “generalconfig” (all lowercase letters), the value should be “generalConfig” (with a capital letter “C”) – that is the convention used in Spring Framework for referencing components in the context of the application. 

Even though the issue is highlighted in the editor, it’s easy to miss this error if the change is made elsewhere without updating the reference value. The compilation process won’t detect this issue and simple unit tests won’t catch it either.

What we need is a minimal set of integration tests and additional static code checks. This is where Qodana comes in handy, as this type of issue is included in the report that JetBrains’ flagship code quality platform generates. 

Spring GeneralConfig Qodana inspections

Application configuration inspections

Configuration issues are annoying. A little typo in a configuration file can cause an application to misbehave or even crash.

Configuration inspections report unresolved and deprecated configuration keys and invalid values in the configuration files of Spring Boot application properties, which can lead to runtime errors. 

For instance, the configuration might include deprecated property names. This may occur when we upgrade the version of Spring Framework in the project but remember to update the configuration accordingly.

Spring Application configuration inspections

Another type of configuration issue involves the misspelling of property values. For instance, in the screenshot above, the value of the spring.devtools.restart.poll-interval property is highlighted in red. This value should be spelled as “5m” instead of “5min”.

Qodana inspections for Spring Data 

Spring Data relies on its method naming convention to generate database queries. Although this approach is very convenient, it’s easy to miss the convention unless you’re paying very close attention.

Code quality Inspections for Spring Data Qodana

In the example above, the convention for the findByType method signature requires the PetType class as a parameter, but Integer was used as a parameter instead. To fix this, we can either extract a JPQL query into a Query annotation for the method or simply change the parameter type.

findByType method Spring inspections, JetBrains Qodana

There are more checks that verify that the code using Spring Data follows the applicable conventions. For instance, you’ll be notified if the method name doesn’t match the property name of the entity.

kotlin resource annotation

Inspections for Spring MVC

Data access isn’t the only place where Spring Framework relies on naming conventions. Another example where you need to be aware of the conventions is the implementation of the web layer.

When working with Spring MVC, typically we refer to external resources or path variables by name. It’s easy to make a typo and then the external resource won’t be resolved.

Inspections in Spring MVC, Qodana code quality

The inspections for Spring MVC can also detect the unresolved references in the PathVariable annotation and missing resources for template engineers like Thymeleaf.

PathVariable annotation and missing resources Spring, JetBrains Qodana

The powerful combination of Spring, Qodana and IntelliJ IDEA

Spring Framework is a popular yet complex framework where a lot of its functionality is based on naming conventions, or relies on component name references that are not validated at compile time.

IntelliJ IDEA validates Spring Framework conventions as you type in the editor, while Qodana builds on top of IntelliJ IDEA’s static analysis engine to provide visibility into the project for the whole team.

As a direct result, you can use Qodana to increase productivity, improve code quality, and provide learning opportunities to developers at various stages of seniority.

Got questions on code quality for the Qodana team?

Reach out to [email protected] – or follow us on X (formerly Twitter) and LinkedIn for code quality updates. You can also view the documentation to get started.

Get a Qodana demo

Subscribe to Qodana Blog updates

By submitting this form, I agree that JetBrains s.r.o. ("JetBrains") may use my name, email address, and location data to send me newsletters, including commercial communications, and to process my personal data for this purpose. I agree that JetBrains may process said data using third-party services for this purpose in accordance with the JetBrains Privacy Policy . I understand that I can revoke this consent at any time in my profile . In addition, an unsubscribe link is included in each email.

Thanks, we've got you!

Discover more

Qodana and c and c++ linters for better code quality.

EAP: JetBrains Qodana Now Supports C and C++ for In-Depth Code Analysis

Introducing JetBrains Qodana’s C and C++ linter, offering in-depth code analysis and code quality for your team, from IDE to pipeline to product.

Kerry Beetge

Create Custom Code Inspections in IntelliJ IDEA – and More – With Qodana 2024.1

Discover what's new in Qodana's latest 2024.1 release with new features and functionality for code quality done right.

Analyzing JavaScript code in a CI Pipeline with TeamCity and Qodana

Improving Code Quality in JavaScript Projects With Qodana

Use JetBrains Qodana to set up static code analysis in an open-source repository, find critical and high-severity issues early, and explore results.

Maksim Grushchenko

How to improve code quality in game development with Qodana and Unity

We tried Qodana on an internal Unity project – Archipelago, a virtual reality app that visualizes sales in the form of mountains. Qodana brings all of Rider’s Unity inspections to CI analysis so the whole team can review code.

Ekaterina Trukhan

Rusmania

  • Yekaterinburg
  • Novosibirsk
  • Vladivostok

kotlin resource annotation

  • Tours to Russia
  • Practicalities
  • Russia in Lists
Rusmania • Deep into Russia

Out of the Centre

Savvino-storozhevsky monastery and museum.

Savvino-Storozhevsky Monastery and Museum

Zvenigorod's most famous sight is the Savvino-Storozhevsky Monastery, which was founded in 1398 by the monk Savva from the Troitse-Sergieva Lavra, at the invitation and with the support of Prince Yury Dmitrievich of Zvenigorod. Savva was later canonised as St Sabbas (Savva) of Storozhev. The monastery late flourished under the reign of Tsar Alexis, who chose the monastery as his family church and often went on pilgrimage there and made lots of donations to it. Most of the monastery’s buildings date from this time. The monastery is heavily fortified with thick walls and six towers, the most impressive of which is the Krasny Tower which also serves as the eastern entrance. The monastery was closed in 1918 and only reopened in 1995. In 1998 Patriarch Alexius II took part in a service to return the relics of St Sabbas to the monastery. Today the monastery has the status of a stauropegic monastery, which is second in status to a lavra. In addition to being a working monastery, it also holds the Zvenigorod Historical, Architectural and Art Museum.

Belfry and Neighbouring Churches

kotlin resource annotation

Located near the main entrance is the monastery's belfry which is perhaps the calling card of the monastery due to its uniqueness. It was built in the 1650s and the St Sergius of Radonezh’s Church was opened on the middle tier in the mid-17th century, although it was originally dedicated to the Trinity. The belfry's 35-tonne Great Bladgovestny Bell fell in 1941 and was only restored and returned in 2003. Attached to the belfry is a large refectory and the Transfiguration Church, both of which were built on the orders of Tsar Alexis in the 1650s.  

kotlin resource annotation

To the left of the belfry is another, smaller, refectory which is attached to the Trinity Gate-Church, which was also constructed in the 1650s on the orders of Tsar Alexis who made it his own family church. The church is elaborately decorated with colourful trims and underneath the archway is a beautiful 19th century fresco.

Nativity of Virgin Mary Cathedral

kotlin resource annotation

The Nativity of Virgin Mary Cathedral is the oldest building in the monastery and among the oldest buildings in the Moscow Region. It was built between 1404 and 1405 during the lifetime of St Sabbas and using the funds of Prince Yury of Zvenigorod. The white-stone cathedral is a standard four-pillar design with a single golden dome. After the death of St Sabbas he was interred in the cathedral and a new altar dedicated to him was added.

kotlin resource annotation

Under the reign of Tsar Alexis the cathedral was decorated with frescoes by Stepan Ryazanets, some of which remain today. Tsar Alexis also presented the cathedral with a five-tier iconostasis, the top row of icons have been preserved.

Tsaritsa's Chambers

kotlin resource annotation

The Nativity of Virgin Mary Cathedral is located between the Tsaritsa's Chambers of the left and the Palace of Tsar Alexis on the right. The Tsaritsa's Chambers were built in the mid-17th century for the wife of Tsar Alexey - Tsaritsa Maria Ilinichna Miloskavskaya. The design of the building is influenced by the ancient Russian architectural style. Is prettier than the Tsar's chambers opposite, being red in colour with elaborately decorated window frames and entrance.

kotlin resource annotation

At present the Tsaritsa's Chambers houses the Zvenigorod Historical, Architectural and Art Museum. Among its displays is an accurate recreation of the interior of a noble lady's chambers including furniture, decorations and a decorated tiled oven, and an exhibition on the history of Zvenigorod and the monastery.

Palace of Tsar Alexis

kotlin resource annotation

The Palace of Tsar Alexis was built in the 1650s and is now one of the best surviving examples of non-religious architecture of that era. It was built especially for Tsar Alexis who often visited the monastery on religious pilgrimages. Its most striking feature is its pretty row of nine chimney spouts which resemble towers.

kotlin resource annotation

Plan your next trip to Russia

Ready-to-book tours.

Your holiday in Russia starts here. Choose and book your tour to Russia.

REQUEST A CUSTOMISED TRIP

Looking for something unique? Create the trip of your dreams with the help of our experts.

IMAGES

  1. How to Make Gradle Kotlin Projects Work Properly With Annotation

    kotlin resource annotation

  2. How to Use The @JvmName Annotation in a Kotlin File

    kotlin resource annotation

  3. Unleashing the Power of Kotlin Annotations

    kotlin resource annotation

  4. Kotlin Annotation Processing Tool. What is it? When to use it?

    kotlin resource annotation

  5. Kotlin Annotation Processing

    kotlin resource annotation

  6. What Is Jvmstatic Annotation In Kotlin And Why We Use It Codevscolor

    kotlin resource annotation

VIDEO

  1. Incremental annotation processors compilation for Kotlin (KAPT)

  2. 25. @Resource -JSR-250 Annotation

  3. Introduction to Kotlin Multiplatform (KMP)

  4. @Inject Annotation in Dagger2

  5. JvmOverloads and when to use it? || Android Interview Questions Answers

  6. Install and Configure Kotlin Plugin in Android Studio

COMMENTS

  1. Improve code inspection with annotations

    Run code inspections. To start a code inspection from Android Studio, which includes validating annotations and automatic lint checking, select Analyze > Inspect Code from the menu. Android Studio displays conflict messages to flag potential problems where your code conflicts with annotations and to suggest possible resolutions.

  2. Annotations

    Annotations. . Annotations are means of attaching metadata to code. To declare an annotation, put the annotation modifier in front of a class: Additional attributes of the annotation can be specified by annotating the annotation class with meta-annotations: @MustBeDocumented specifies that the annotation is part of the public API and should ...

  3. Kotlin Annotations

    2. Applying Annotations. In Kotlin, we apply an annotation by putting its name prefixed with the @ symbol in front of a code element. For example, if we want to apply an annotation named Positive, we should write the following: @Positive val amount: Float.

  4. Resource annotations and @IntDef and @StringDef

    Are there any plans to introduce support for integer annotations for resources in Android, such as @StringRes, @ColorRes, @LayoutRes, along with the lint checks around them. Also, it would be nice if we could get support for @IntDef and @StringDef. ... Kotlin 1.0.2 includes Android Lint diagnostics, so @ColorRes, @LayoutRes and other ...

  5. How Kotlin Annotations Work

    How Kotlin Annotations Work — Part 1. Android developers can build complex apps with annotations scattered throughout, such as @Provides from Dagger or @ColorRes from AndroidX, without fully understanding how they work; they can almost feel like magic. This article will unshroud some of the magic by exploring the three main mechanisms that ...

  6. A Comprehensive Guide to Understanding Kotlin Annotations

    Kotlin is designed with Java interoperability in mind, including annotations. Here are some rules you need to stick to: If you use a Java annotation with multiple parameters, use the named argument syntax in Kotlin. If the Java annotation has the value parameter, you need to specify it in Kotlin.

  7. Annotations

    Annotations are a form of syntactically-defined metadata which may be associated with different entities in a Kotlin program. Annotations are specified in the source code of the program and may be accessed on a particular platform using platform-specific mechanisms both by the compiler (and source-processing tools) and at runtime (using reflection facilities).

  8. Comprehensive Guide to Annotations in Kotlin

    1. Introduction to Annotations. Annotations in Kotlin are a mechanism to add extra information or metadata to your code, without affecting the runtime behavior. They provide a way to convey important details to the compiler, tools, or other developers. Annotations are defined using the @ symbol followed by the annotation name and placed ...

  9. Introduction to Annotation Processing in Kotlin: The Basics

    Annotation processing is a tooling feature provided by the Kotlin compiler, which allows us to generate additional source files during compilation based on annotations present in our source code.

  10. androidx.resourceinspection.annotation

    Quickly bring your app to life with less code, using a modern declarative approach to UI, and the simplicity of Kotlin. Explore Modern Android Adopt Compose for teams

  11. Mastering in Kotlin Annotations

    To make an annotation repeatable in Kotlin, you need to mark its declaration with the @kotlin.annotation.Repeatable meta-annotation. This ensures that the annotation can be repeated both in Kotlin and Java. The key difference between Kotlin and Java in terms of repeatable annotations is the absence of a containing annotation in Kotlin.

  12. kapt compiler plugin

    Measure the number of files generated with annotation processors. The kotlin-kapt Gradle plugin can report statistics on the number of generated files for each annotation processor. ... An output path for the generated class files and resources. stubs (required): An output path for the stub files. In other words, some temporary directory.

  13. kotlin

    Thanks for contributing an answer to Stack Overflow! Please be sure to answer the question.Provide details and share your research! But avoid …. Asking for help, clarification, or responding to other answers.

  14. Kotlin annotations

    Annotations are a feature of Kotlin that allows the programmer to embed supplemental information into the source file. This information, however, does not changes the actions of the program. This information is used by various tools during both development and deployment. Annotations contains the following parameters most frequently and these ...

  15. Kotlin

    // Apply the org.jetbrains.kotlin.jvm Plugin to add support for Kotlin. id 'org.jetbrains.kotlin.jvm' version " $ kotlin_version " // Apply the application plugin to add support for building a CLI application in Java. id "com.google.devtools.ksp" version " $ ksp_version " id 'application'} // KSP - To use generated sources sourceSets. main

  16. Moscow Oblast

    Map of the Moscow Oblast. The Joseph-Volokolamsk Monastery in Volokolamsk. Flag Coat of arms. Moscow Oblast (Russian: Моско́вская о́бласть, Moskovskaya oblast) is a federal subject of Russia.It is located in western Russia, and it completely surrounds Moscow.The oblast has no capital, and oblast officials reside in Moscow or in other cities within the oblast.

  17. [2405.20315] ANAH: Analytical Annotation of Hallucinations in Large

    Each answer sentence in our dataset undergoes rigorous annotation, involving the retrieval of a reference fragment, the judgment of the hallucination type, and the correction of hallucinated content. ANAH consists of ~12k sentence-level annotations for ~4.3k LLM responses covering over 700 topics, constructed by a human-in-the-loop pipeline. ...

  18. kotlin.annotation

    Library support for the Kotlin annotation facility. This meta-annotation determines that an annotation is a part of public API and therefore should be included in the generated documentation for the element to which the annotation is applied. This meta-annotation determines whether an annotation is ...

  19. Elektrostal

    Elektrostal. Elektrostal ( Russian: Электроста́ль) is a city in Moscow Oblast, Russia. It is 58 kilometers (36 mi) east of Moscow. As of 2010, 155,196 people lived there.

  20. Elektrostal, Moscow Oblast, Russia

    Elektrostal Geography. Geographic Information regarding City of Elektrostal. Elektrostal Geographical coordinates. Latitude: 55.8, Longitude: 38.45. 55° 48′ 0″ North, 38° 27′ 0″ East. Elektrostal Area. 4,951 hectares. 49.51 km² (19.12 sq mi) Elektrostal Altitude.

  21. Hi5: 2D Hand Pose Estimation with Zero Human Annotation

    We propose a new large synthetic hand pose estimation dataset, Hi5, and a novel inexpensive method for collecting high-quality synthetic data that requires no human annotation or validation. Leveraging recent advancements in computer graphics, high-fidelity 3D hand models with diverse genders and skin colors, and dynamic environments and camera movements, our data synthesis pipeline allows ...

  22. AnnotationTarget

    compareTo. Compares this object with the specified object for order. Returns zero if this object is equal to the specified other object, a negative number if it's less than other, or a positive number if it's greater than other. infix fun <T> Comparable<T>.compareTo(other: T): Int.

  23. Static Code Analysis for Spring: Run Analysis, Fix Critical Errors, Hit

    When working with Spring MVC, typically we refer to external resources or path variables by name. It's easy to make a typo and then the external resource won't be resolved. The inspections for Spring MVC can also detect the unresolved references in the PathVariable annotation and missing resources for template engineers like Thymeleaf.

  24. Savvino-Storozhevsky Monastery and Museum

    Zvenigorod's most famous sight is the Savvino-Storozhevsky Monastery, which was founded in 1398 by the monk Savva from the Troitse-Sergieva Lavra, at the invitation and with the support of Prince Yury Dmitrievich of Zvenigorod. Savva was later canonised as St Sabbas (Savva) of Storozhev. The monastery late flourished under the reign of Tsar ...