The Full Guide to ANNOTATIONS In Kotlin

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hi guys and welcome back to a new video in this video I will show you how you can make use of annotation classes or rather just annotations in kotlin so we all know these that we can annotate our stuff with these existing annotations like for example if we have a test case we we do have the test annotation which is only accessible in the test Source it um but that basically tells junit in this case that the function we're annotating this with is a test case and there are a lot of these predefined annotations but how can we actually make use of these and create our own ones and then also tell our functions and our classes our fields that if an annotation that we created is added there that we want to do something specific so in this video you will learn how and I want to start with a more theoretical example so you just get to know annotation classes a little bit more and how we can work with these how we can process these and then I will get to a more practical example that shows you how you can actually yeah use these in your Android projects in a very useful weight so let's assume we do have something like a data class called user each user has a name and let's say each user has a birth date then we can do it like this um but since the birth date is actually a string here but can actually only take a certain format of the date so we actually only want to be able to pass dates here as a string and not any other kind of string for example like a name so what we could do here is we could use an annotation to enforce this and to create this annotation that we can basically Define some kind of regular expression so regex expression that this specific field must fulfill and if not that we simply throw an exception so we can achieve this by creating annotation class that is how we Define our own annotation and we can call this for example like allowed regex and we can then give this a Constructor just like any other class and we can say we pass the regex here as a string that we want a certain field field to fulfill to kind of fit you how about this right now won't really work because if we Define such an annotation class then we again need to make use of annotations to kind of first of all Define where we can use this annotation how it's kind of processed and things like that and there are multiple common annotations we use for annotation classes to Define exactly that on the one hand that is Target so add Target and here we need to specify what we kind of want to be able to add this annotation for so we can say annotation Target and you can see we have function field class annotation class so a lot of these targets that let us Define that okay this annotation is actually only applicable to functions if we want that then we can Define that here and you can see that as a VAR Arc so you can of course Define multiple of these targets if you want your annotation for example to be applicable to classes and functions you simply add these two here and in our case we want this to be applicable to fields since we want to add this to our birth date which is yeah just a field of our class could also just be a member variable also so we just add that here then some other common annotations we can use for annotation classes is on the one hand must be documented that basically just means if we take a look at the documentation here that this annotation that we Define here so our allowed regex annotation will also be included in the public API so if you generate some kind of documentation for your source code and you have this annotation for your notation class then your annotation will also be contained in the generated documentation for your code let's remove that and take a look at the retention annotation which is also commonly used here we need to specify this annotation retention you can see the oops notation retention you can see the default is runtime um so what can we actually Define with that with this annotation retention we basically Define where this and where and when this annotation is actually accessible usually you can leave this at the default um runtime which means this annotation is kind of baked into the final binary binary file so your APK file or rather your Java later on and it is also accessible via reflection in your code then we have source which means it is only accessible via reflection but not it is not contained in the binary anymore so you can pick that if you really don't need to kind of process this annotation after you've actually already built or rather generated your binary file and then we do have the binary retention which means that we cannot access our annotation with reflection in our code however it is baked into the binary file this is for example um used for the program annotation which is keep um so that is basically just a notation that tells us hey or that tells progod hey please don't obfuscate this class we annotate this with and since proguard operates on the final Java file and not it's not kind of part of our source code this annotation needs to be accessible in the final binary file that would be one use case for example for the binary retention just to give you some kind of examples you can yeah imagine what that could be used for and one last annotation that we can commonly use for annotation classes is ADD repeatable and that should be self-explanatory that basically says that if we have this notation for our annotation class then we can repeat The annotation multiple terms for the same field so in this case this doesn't make any sense but sometimes yeah it would make sense and then you can use this annotation to Define that you want this behavior let's remove that again and just keep this target to make it applicable to fields and now the next step is if we annotate our birth date with our loud regex annotation now and pass some kind of regex like this for example so this is a very very simplified regex for dates but it basically just expects four digits at the start than a dash so that will be for the Year oops then the second number here it expects two digits for the month Dash again and then uh yeah two more digits for the day so we can now add this annotation to our field you can also see if we would add that here to our class with some kind of empty string it wouldn't work because we did not add this um class as an annotation Target if we would want that we could add that here like this and I could see then you can see the error is actually gone but in this case it wouldn't make any sense so we leave it like that how can we now actually process this annotation because right now we did not Define the behavior that we actually want that we thrown exception if this regular expression is not met in this comma and this certain field here and we do need to process that in the class here where we actually add this if you use that at multiple places in your code then you could also use some kind of helper function also which you can then easily yeah just reuse in different classes but let's keep it simple here and just have our knit Block in which we want to verify that this regex is met and here we can now say we refer to the fields which is this so we refer to our user class double colon class.java dot declared Fields with that we basically get a list of all Fields this user class has we can then use that to Loop over it get a reference to each field whoops like this so this will now be looped over name and birth date and then for each field that could contain multiple annotations so we also want to Loop over that so for each annotation we can now actually check if the field contains a specific annotation like in our case our allowed regex annotation so we can say if a field that is annotation present here we can pass The annotation type which is in this case allowed reg X double colon class Java if that's the case we know that the field we're currently looping over has our allowed regular notation so if we know that we added this annotation we now need to verify or we need not only to retrieve this regular expression of that and then check if our birth date is actually matching that expression and to do that we first of all need access to this regex variable here we can do this with a Val regex and that's equal to our field dot get annotation to yeah just get a reference to that annotation we're dealing with we need to pass the type of that annotation which is allowed regex double colon class Java and now we get a reference to that we can add that regex which is now referring to exactly that variable and then we can check if our regex dot two regex so we actually get a regex object we can use to yeah match a certain string and then we can say that matches our birth date in this case if you would have this annotation for multiple fields in your class you would also need to kind of check if you're actually dealing with your birthday field here but in this case let's keep it simple and just um yeah always assume that if we have this annotation we're dealing with this birth date if that is false that means the regular expression is not met for our date string then we simply want to throw an exception in this case something like an illegal argument exception and we can say um birth date is not a valid date and then we can yep just print the date like this and of course in this case you could also simply um not use a notation here so you don't have the user to achieve this kind of behavior you could also as well just have an init blog and then check if the birthday is is a valid date you could also make a helper function for that to validate that with your regular expression or so but yeah that was rather just to demonstrate how we can use regular expression in our code and in pretty much all scenarios you don't have to use these these can make your life easier but it's not like you can do things with these annotations you can't do with other things at least not in this normal context if you write a library that generates a lot of code then you often need these annotations for example if you if you're dealing with a room Library the authors of that of course needs to kind of Define if your if a class is annotated with a database that you generate a certain piece of code for that that is a scenario where you have to use annotations about usually if you just have your kind of app and you don't write a library to generate code then there are also usually ways to solve your problem without an annotation but this can make your life easier so now that we understand how annotations work let's get to more practical example and if you're an Android developer I'm sure you know a retrofit and that is why I already added the dependencies here to show an example when using retrofit here so I added these dependencies make sure to add these as well if you want to follow and what I basically want to show you here is if you have some kind of remote API you're dealing with you're using retrofit and there are certain routes which are simply not authenticated so which might not need an attached token and there are routes which do need that and I will show you now how we can actually create an annotation that we can add to our retrofit API call functions if a certain route is authenticated and then we create an Interceptor which will automatically create which will automatically attach a certain token if that annotation is present so let's start one step at a time and we go to our root package and create a class like my API there won't be anything very functional we just want to have some kind of practical environment here and I will use the Json placeholder API for that which is just an free public API to experiment with apis first of all I want to have a suspend function to get a user and here we simply have a get request to slash users and we refer to the first user then we want to have another suspend function to get a post here we have a get request to slash post slash one and let's now assume that this get user function does not need authentication so you don't need to attention token for that but this get post function does need that so in a real-life context that could for example be a login function where you don't need to attach a token because you need to log in to get your token and it could be something like a function that gets your current profile which you of course need a token for otherwise anybody could retrieve your profile data so let's now go ahead and create an annotation class here which we call authenticated and with if that annotation is now present at such a function we want to add our token to a request so we say The annotation uh actually the target is annotation Target and in this case I want to be able to add those two functions and we say the get post route is authenticated so here we do we want to attach a token then how can we now check if this annotation is present and actually attach the token if it is present so let's go ahead and create an auth Interceptor an Interceptor is basically just something that will run on every single request your API client makes and then kind of yeah modify your request because that is what we want to be able to do here we want to add a header if that annotations actually present so that is an interceptor we need to override The Intercept function and here we just get a reference to the chain which contains our request and we can return a response which is basically the modified request the way we do this with retrofit is a little bit special we need to first of all get a reference to this invocation you can see this comes from retrofit and this is basically just a function invocation so the function that we actually call here where we added this annotation and we do get this by saying is equal to chain that request and that tag and here we say we tag this with an invocation double colon class of java if that is not also that's not existent then we simply want to return chain that proceed so we simply proceed with the request that is already contained in the chain so we don't modify it at all and now with this invocation reference here we can now have a variable a Boolean should attach auth header and that is equal to invocation that method to refer to the method of that invocation since that is where we added this annotation and here we now have the option to actually access the annotations and we can check if we actually have any um any annotation where it annotation class is actually equal to our authenticated annotation so this is really just a special way how we do this with kind of retrofit because we don't really have access to the class where we added this annotation here for a rather a reference to the API interface and that we add this auth Interceptor for so we need to do it this way it's just what you need to do if you want to do this with retrofit then we can check if our should attach auth had a Boolean is true then we want to return chain dot proceed so we proceed with a modified request in this case and we can say chain dot request dot new Builder to be able to modify it I want to add a header in this case we want to add an authorization header and the value of that is yeah just let's say my token of course in a real app you would attach a real token here then we can say that build and else if that's not the case we simply proceed with the initial request unmodified like this and this will now run for every single request we make with our API client and then just check if this annotation is present for that certain function and if so it will attach this token so let's try this out first of all going to manifest and adding the internet permission uses permission internet and then going to main activity and scrolling up let's just initialize our API client here private Val API but lazy like this and here we can say retrofit data Builder we set the base URL to this so that is the API we'll actually use to make our requests to just that we have some kind of valid data and then we want to add a client which is an okay HTTP client where we need to add these interceptors so you can say Okay HTTP client um that Builder we want to say I want to add an Interceptor which is in this case our auth interceptor we then want to add another Interceptor which is our OK http logging into it's just HTTP logging Interceptor that is the dependency I actually added here HTTP logging um that is the dependency here which basically just logs our whole request so that Json responds Json request all the headers so that we can just see that the header is really attached so let's create that here and we set the log level to body like this and then we can say that build we want to add a converter Factory just for Json converting which is Moshi convert Factory that create and then we can say that builds dot create and I want to create our my API like this cool let's first of all try our user regex here over user class if we create a user here that is equal to a new user then we say the name is I don't know Peter and the birth date is something like 18 for uh it's actually the other way around this let's say 2002 and this would be our date let's make it a validate here like this well let's actually start with an invalid date let's add a letter here which would then not fulfill our regex if we then launch this here on our device then we should actually see that if this app is launched we get a log for that exception that we throw here so this illegal argument exception if we take a look here now it's launching and you can see we actually do get it here um oops what did I do here um a birth date is not a valid date and here it actually prints our date if we remove this each year so what is a validate we relaunched this then we should not actually get an exception this time so if we take a look here scroll down there is no exception so that is working perfectly fine let's try the um our other thing we did here with retrofit by actually saying okay lifecycle scope launcher 13 here and here we simply want to say our API get post and API dot get user to just have calls to this launch this app and then in here in our log ad we can actually filter for okhgp to get the logs you can see um for our user function which is not authenticated we did not add The annotation here we actually don't have the header for our token so there is no authorized header in here but if we scroll up to our other our other call to posts and we take a look here um here it is here's our authorization header with our my token because we added The annotation here so that is a very cool way now how you can actually add certain tokens in your project and if you have a large project this is really you know a really good way to actually do that if that logic kind of differs for different routes so I hope this actually helped you to understand how annotations and annotation classes work how you can process these and just use a new project to make your code a little bit cleaner if so you will definitely also love my premium courses which are more advanced and prepare you to become an industry ready Android developer if that sounds cool to you check the first link in this description and apart from that I wish an amazing rest of your week and see you back in the next video bye bye foreign
Info
Channel: Philipp Lackner
Views: 30,293
Rating: undefined out of 5
Keywords:
Id: qdnhQzVGywQ
Channel Id: undefined
Length: 21min 32sec (1292 seconds)
Published: Sun Jan 29 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.