Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there an android annotation for checking the pattern of string parameter?

Problem

I am working with Android and Kotlin and I would like to have an annotation to check if a constant String parameter (to a function or constructor) matches a certain pattern (regex). I read about the Pattern Annotation, but am not sure if it applies to my problem and if it is available with Android.

So when i would have code like this

fun foo(@MatchesPattern("a*b") bar: String) = println(bar)

then

foo("aaaab")

should compile just fine, but

foo("bb")

shouldn't.

Is this possible, preferably without any third party libraries? If yes, how would I implement an annotation like that? (sorry, I'm not familiar with writing my own custom annotations)

Background

I would like to pass words with hyphen-separated syllables as params, however a word should not have more than 3 syllables (that means max. 2 hyphens per word). I'm aware I could also achieve this with default params, but I think an annotation would be a more elegant way to achieve this.

like image 809
LPeteR90 Avatar asked Jun 14 '18 11:06

LPeteR90


1 Answers

It's not quite as straightforward in Android as it would be otherwise because you will have to make a new project (java library) where you can put your annotation. The process looks something like this (not tested).

  1. Create a new java library with android studio as a module in your project (select your project root, right click, new module). This will add a folder, for example lib if you don't change its default, with the class you specify, such as MyCustomAnnotationProcessor.

  2. In your app directory, go to the build.gradle and modify it to include sourceCompatibility and targetCompatibility like so:

    android {
        ...
        compileOptions {
            sourceCompatibility = JavaVersion.VERSION_1_8
            targetCompatibility = JavaVersion.VERSION_1_8
        }
    }
    
  3. Then do almost the same thing in your lib's build.gradle file (if not already present after rebuilding at step 2)

    apply plugin: 'java-library'
    
    dependencies {
        implementation fileTree(dir: 'libs', include: ['*.jar'])
    }
    
    sourceCompatibility = "1.8"
    targetCompatibility = "1.8"
    
  4. In the lib folder, create a new class for the annotation (an @interface) like so:

    @Retention(RetentionPolicy.SOURCE)
    @Target(ElementType.PARAMETER)
    public @interface PatternMatches {
        String value() default ".*";
    }
    
  5. Modify your annotation processor created in step 1. Note that this extends javax.annotation.processing.AbstractProcessor, which is only available here because we're in a java library.

    @SupportedAnnotationTypes("your.package.PatternMatches")
    @SupportedSourceVersion(SourceVersion.RELEASE_8)
    public class MyCustomAnnotationProcessor extends AbstractProcessor {
        private ProcessingEnvironment processingEnv;
        @Override
        public synchronized void init(ProcessingEnvironment env){
            processingEnv = env;
        }
        @Override
        public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
            Set<? extends Element> elements = roundEnv.getElementsAnnotatedWith(PatternMatches.class);
            Set<VariableElement> params = ElementFilter.fieldsIn(elements);
            for (VariableElement param : params) {
                String val = param.getConstantValue();
                String regex = param.getAnnotation(PatternMatches.class).value();
                if (!val.matches(regex)) {
                    processingEnv.getMessager().printMessage(
    Diagnostic.Kind.ERROR, "Regex match failed", param);
                }
            }
            return false;
        }
    }
    
like image 132
geco17 Avatar answered Sep 29 '22 10:09

geco17