How to add conditions to Java Bean validation?

Published / by msaladin / Leave a Comment

Today I faced a very common problem and I did not find out how to solve it for some time. I am using Java Beans Validation (JSR 380), so this means that I can use annotations in my class and at the time of validation, my framework (in this case Springboot) is automatically trying to validate the values of the class.
Example:

public class ClassToValidate {
  @NotNull
  private String email;
}

This works fine, and I can add annotations like:

  • @NotNull
  • @Size(min = 2, max = 64)
  • etc…

But my problem was that I wanted to have a special kind of validation:

  • If the field is null, this is ok for me.
  • But if the field is not null, then I want to add special validation (like checking that the minimal and maximal length of the string is validated and is between 2 and 64 chars).

The Java Beans validation provides a very helpful way how to create custom annotations, and this is what is needed to have such a conditional (OR) validation logic. Just create your own annotations, and combine them using OR:

public class ClassToValidate {
    @ConstraintComposition(CompositionType.OR)
    @Null
    @Size(min =2, max=256)
    @Target({ElementType.METHOD, ElementType.FIELD})
    @Retention(RetentionPolicy.RUNTIME)
    @Constraint(validatedBy = {})
    public @interface EmailOrNull {
        String message() default "Not valid";

        Class[] groups() default {};

        Class[] payload() default {};
    }

    @EmailOrNull
    private String email;
}

I found some interesting information here:
JBOSS Hibernate validator documentation

Searching git repo for source-code change

Published / by msaladin / Leave a Comment

Today I wanted to search for a Java class in my git repository that no longer exists. I can recall that I had used some code snippets in a class that no longer exists, but I cannot recall the class name, and I cannot recall which commit message I used to remove the class from the repository. My question was: Can I full-search my git repo?

Answer: Yes. It is possible to search the whole git for a regular expression. Let’s say I knew that in the class I was searching, I had the following code snippet “Jwts.builder()”, so I can search the whole repository for this snippet:

git grep "Jwts.builder()" $(git rev-list --all)

The result I get is a list of all files where the search string exists, and the git commit hash. With this you can checkout the revision (git commit hash), search for the file, and then continue to navigate from there on using your favorite IDE.

Links:

Renew JWT token in Angular

Published / by msaladin / Leave a Comment

Currently I am working on a small project with a frontend application in Angular (version 10) and a backend in Springboot. Because this application is rather small I decided to issue the JWT token in the backend and not use an external Authorization provider like Azure. So the workflow goes like this:

  • User enters credentials
  • Frontend calls backend /login, backend verifies hashed password and if successful returns a self-signed JWT token
  • Frontend stores the JWT token in session-storage, and sends the token in the http header for each subsequent request
  • In this blog post I discuss how the frontend app assures that there is always a valid token sent along with each http request to the backend.

    Step 1: Include token in http header

    In Angular you can define a http interceptor which checks the session-storage for the token, and includes it in the http header. Let’s reuse an existing header for this which is the Authorization header. See RFC 6750 for more details. The interceptor code looks quite simple:

    @Injectable()
    export class AuthInterceptor implements HttpInterceptor {
    
        intercept(request: HttpRequest, next: HttpHandler): Observable> {
            const idToken = this.localSessionService.getIdToken();
            if (idToken) {
                const cloned = request.clone({
                    headers: request.headers.set('Authorization', 'Bearer ' + idToken)
                });
                return next.handle(cloned);
            } else {
    
                return next.handle(request);
            }
        }
    }
    

    The interceptor needs to be defined in the Angular module as a provider, so my app.module.ts file includes this:

    ...
    providers: [
      {provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true},
      {provide: HTTP_INTERCEPTORS, useClass: ErrorInterceptor, multi: true}
    ],
    

    Step 2: Renew token

    But a token is not really valid forever, e.g. in my application the token will be valid for 60 minutes. After that, the token is no longer valid, and when the frontend application would not check for this use-case, after 60 minutes, the token expires, the backend returns a 403 http error code, and the frontend application displays the login-screen again… This is not really user-friendly.

    What I want to achieve is that the token is renewed automatically, say, when the token is only 30 minutes valid. There are a lot of OAUTH2 libraries which do the token-renewal deeply hidden in an own iframe (e.g. MSAL Angular library) and don’t need any special implementation in the frontend application.

    But in my frontend app I don’t like this kind of magic, so I included it like this:

  • Whenever there is a call to the backend, check whether the time to live (TTL) of the token is smaller than 30 minutes.
  • If yes, then (in the background) invoke a call to /renewToken endpoint and renew the token.
  • Nevertheless, as the token is still valid 30 minutes, the ongoing http call can proceed.
  • It could be that there are lot of http requests going on, and we don’t want to request a token-renewal several times (when the token-renewal request takes too much time), so we need to make sure to note whether we have sent a token-renewal-request, and only send new renewal-requests when there was no request sent earlier. The whole logic takes place in the same interceptor as before:

    @Injectable()
    export class AuthInterceptor implements HttpInterceptor {
    
        private renewTokenRequestSent: boolean;
    
        constructor(private localSessionService: LocalSessionService,
                    private readonly httpHandler: HttpBackend) {
        }
    
        intercept(request: HttpRequest, next: HttpHandler): Observable> {
            const idToken = this.localSessionService.getIdToken();
            if (idToken) {
    
                // *********************************** Changes for token renewal *******************
                const expiresAt = this.localSessionService.getIdTokenExpiresAtAsUnitTimestamp();
                const loggedInTTL = moment.duration(moment(expiresAt).diff(moment())).asSeconds();
                if (!this.renewTokenRequestSent) {
                    // Check age of token and if necessary, renew it
                    if (loggedInTTL < (30*60) ) {
                        this.invokeRenewTokenAysnc(idToken);
                    }
                }
                // *******************************************************************************
                const cloned = request.clone({
                    headers: request.headers.set('Authorization', 'Bearer ' + idToken)
                });
                return next.handle(cloned);
            } else {
    
                return next.handle(request);
            }
        }
    }
    

    First, we calculate the TTL of the current token using moment.js. To make this calculation faster I store the Unix timestamp (number) in the localSessionService (moment.valueOf()). If the TTL is smaller than our threshold (30 minutes) the method invokeRenewTokenAysnc is invoked. After that, the ordinary http request continues (next.handle(cloned).

    The method invokeRenewTokenAysnc is quite straight-forward:

  • Don't use an ordinary httpClient as this would mean that there are http interceptors, and we don't want to have http interceptors for the renewal call (this could lead to an infinite loop where the interceptor calls itself infinite times)
  • Make sure that in case of an error the flag (this.renewTokenRequestSent) is reset so that another renewal request will be sent in the future (where maybe the backend server is up and running again)
  • I thought long about error-handling, but actually the error handling callback does not need to do much except log the exception. There is an ongoing http request, and this ongoing http request has a valid error handling. The token-renewal request is invoked in the background, and when the token-renewal fails, our application can do nothing except to try again and again until it works, or until the TTL of the existing token times out.

        private invokeRenewTokenAysnc(idToken: string) {
            // Create own httpClient so that there are no interceptors (e.g. this interceptor) in it, plain vanilla http connection
            const httpClientForRenewal = new HttpClient(this.httpHandler);
            const renewHeaderMap = {
                Authorization: 'Bearer ' + idToken
            };
            const options = {
                headers: new HttpHeaders(renewHeaderMap),
            };
    
            this.renewTokenRequestSent = true;
            httpClientForRenewal.get('/todo/secured/v1/renew', options)
                .pipe(take(1))
                .subscribe(
                    loginResp => this.callbackSuccessRenewToken(loginResp),
                    err => this.callbackErrorRenewToken(err),
                    () => this.callbackCompleteRenewToken()
                );
        }
    
        callbackSuccessRenewToken(authResult: LoginResponse) {
            this.localSessionService.loginSuccessful(authResult);
        }
    
        callbackErrorRenewToken(err: any): void {
            console.error('Error while renewing token. Ignore error and continue (and try again to renew token).');
            // if (err.error instanceof ErrorEvent) {
            //     // *************************************************************************************
            //     // Something could go wrong on the client-side such as a network error that prevents the
            //     // request from completing successfully or an exception thrown in an RxJS operator.
            //     // These errors produce JavaScript ErrorEvent objects.
            //     // *************************************************************************************
            // } else {
            //     // *************************************************************************************
            //     // The backend returned an unsuccessful response code.
            //     // The response body may contain clues as to what went wrong.
            //     // *************************************************************************************
            //     if (err.error.code) {
            //         // Cool, we have a error which we can interpret because it contains the field "code"
            //     } else {
            //         // *************************************************************************************
            //         // We received unknown body, but status is still ok. Mostly this happens when a Proxy/
            //         // LoadBalancer in-between returns a HTML error page.
            //         // *************************************************************************************
            //     }
            // }
            this.callbackCompleteRenewToken();
        }
    
        /**
         * Complete the renewal call, make sure to invoke this method in case of error as well
         */
        callbackCompleteRenewToken(): void {
            this.renewTokenRequestSent = false;
        }
    

    Hope that helps others!

  • Angular.io App – Deploying is not so simple

    Published / by msaladin / Leave a Comment

    I tried to learn a little bit Angular.io, which has a very strange version-history which makes it cumbersome to find solutions to issues and problems in a simple manner. So in this post, I talk about the new AngularJS, currently in version 5.

    I played with the tutorial (https://angular.io/guide/quickstart), and after having played around with it, I wanted to make sure that it does not only work locally with my own ng serve webserver, but with a real production webserver on which I host this website.

    Unfortunately, I experienced two problems with deploying it.

    1. Base HREF

    First, I don’t want to have my AngularJS app as my homepage… I just wanted to have it inside a neat folder called “ng01”. When I created the deployment with:

    ng build --prod
    

    and copied the whole dist folder to the ng01 folder of my website (hosted with Apache httpd), nothing happend, and when I checked the Javascript console, I saw that the Javascript files which were created by angular-cli will not load. The problem is that the default base href is:

    <base href="/">
    

    So this means that when including JS files like this:

    <script type="text/javascript" src="inline.b9fd455402f26b103f03.bundle.js"></script>
    

    won’t work, because the JS files are inside a folder ng01, and not in the root folder.

    Solution:

    Use the –base-href command line parameter for the generation of the dist folder:

    ng build --prod --base-href=/ng01/

    2. Rewrite rules for Angular Routing

    But then, this was not enough. It still did not work.

    The initial routing in the tutorial worked fine when deployed on my website, but as soon as I hit the reload button, it did not work anymore. It gave me a 404 error, which is clear enough. In the Angular tutorial, they write that the URL of a detail-page can be created like this:

    { path: 'detail/:id', component: HeroDetailComponent },
    

    This is a really cool feature… but when you think about it, it just cannot work. it cannot work because an ordinary webserver like httpd does not know anything about the URIs like /ng01/detail/33 or /ng02/detail/77…

    I did not find out the real correct way how to do this (In java, you would define a context path with wildcards in your web.xml and define a Servlet for it), but at least I found a workaround. I just redirect all the 404 error messages to the index.html page, and then Router component of AngularJS seems to do the rest.

    Solution:

    A very nice feature of httpd is that you can have different configuration per directory, using a .htaccess file. So I created a .htaccess file for my ng01 folder where all my files are located:

    RewriteEngine on
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    
    # not rewrite css, js and images
    RewriteCond %{REQUEST_URI} !\.(?:css|js|map|jpe?g|gif|png)$ [NC]
    RewriteRule ^(.*)$ /ng01/index.html?path=$1 [NC,L,QSA]
    

    This worked, now the NG tutorial can be deployed on my website…

    Gradle UP-TO-DATE Check and exception handling

    Published / by msaladin / Leave a Comment

    I really feel the time I am quite old sometimes. I am now programming for about 22 years, and exception handling was always an important part of development. This seems to be no longer true.

    Gradle is a great build system, it is really nice and you can script your build logic using Groovy, which is better than using XML (ANT) or using only convention (Maven). I am working with Gradle now for about 6 month, and I really like some of the concepts… but exception handling is really hard.

    For example, Gradle has the concept that there is some logic which just knows whether a build task needs to be executed or not. For example, if you have a task which compiles Java, and you know all the input files, and the output files, you can compare the input/output from the last build, and the current build, and when the input/outputs did not change, then you don’t have to do the compilation again. This is quite a good idea, so normally, when you build a Gradle project you experience a lot of tasks which just say:

    taskname - UP-TO-DATE

    This means that the task is not really executed. Gradle has some logic to know all the inputs and outputs of the tasks, so it can compare them, and if they are the same, just ignore the task for this run and don’t execute it. This is really fine as long as it works.

    I had a task which copied some JS files into a directory, it too the JS files from a node_modules folder where it downloaded the files first, and then copied them to a generated folder. This would mean that when I delete the destination folder, then the task must really be executed again, because otherwise the file is not copied. When the file is not copied, it is not part of the delivery, and we remark this only when we have successfully deployed the artifact to a system that something is wrong (runtime exception).

    The problem was that Gradle always thought that the task was up-to-date… OK, clearly, there was some error in this. With gradle, you can use command-line-parameters to get more information, like -i for info and -d for debug. I tried this to find out why Gradle thinks that my Copy-task is up-to-date, but the debugging output gave me no real value. There was no hint why the task was up-to-date in the debugging output.

    To make this one short: The Gradle guys had a really good idea that tasks should not be executed when the input/output match. This works great. But we as developers make errors, and when we make errors, we want that a tool provides us with a meaningful message, at least in the debugging output.

    What really was the problem in my case was that I defined the tasks outputs wrongly, so the directory for the output did not exist in the previous run, and as it does not exist now, the current run does not see any difference and just says UP-TO-DATE.

    My whole debugging session, the time I lost with it, could really have been decreased by providing a meaningful debugging-output… I will try to contribute my logging to the gradle GitHub project, hopefully they will include it and this will safe some time for other devs.