How to get the value of an Annotation type Element ?


package com.test;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;



public class ValueAnnotation {


    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.TYPE_USE)
    protected @interface  TypeUse {
        int value();
    }

    @TypeUse(value = 0) class Test<T>{

    }
}

Processor


    private void processEnclosedElements(List<? extends Element> enclosedElements,
                                         RoundEnvironment roundEnv) {

        for( Element e : enclosedElements ){

            if (e.getKind() == ElementKind.CLASS){

                System.out.println( "Annotation [" + e.getAnnotationMirrors() + "] [" + e  + "]");

                processClassTypeParameters(e);
            }
        }
    }

    private void processClassTypeParameters(Element e) {

            for( AnnotationMirror am  : e.getAnnotationMirrors() ){

                for(Map.Entry< ? extends ExecutableElement, ? extends AnnotationValue> m : am.getElementValues().entrySet()){

                    System.out.println( "[" + m.getKey() +"][" + m.getValue() + "]");

                }

            }
    }


Annotation [@com.test.ValueAnnotation.TypeUse(0)] [com.test.ValueAnnotation.Test]
[value()][0]

IntersectionType

I came across this code that uses a cast to assign a Lambda expression to a marker interface in Angelika Langer’s explanation.

Serializable f2
= (BiPredicate<String,String> & Serializable)
(s,t) -> s.equalsIgnoreCase(t);

As I was curious about this I tried to detect an intersection type (T extends String & @IntersectionType.TypeUse(value = 2) Serializable) and print the annotation applied on one of its bounds.

The result is

Annotation [] [com.test.IntersectionType.Test]
Annotation [[]] [java.lang.String]
Annotation [[]] [java.io.Serializable]

This could be a JDK 8 bug at this time. I am getting nothing.

I am using

java version "1.8.0-ea"
Java(TM) SE Runtime Environment (build 1.8.0-ea-b123)
Java HotSpot(TM) 64-Bit Server VM (build 25.0-b65, mixed mode)

I presumed there is a javax.lang.model.type.IntersectionType that will match T extends String & Serializable. So I though there is a TypeMirror that I can check for that type. But it does not seem so.

I will update later when I get a proper result.

Update : The method is updated and it works partly. I am getting the intersection type. But I think one cannot get the annotation type of the intersection type directly because the annotation is applied on each of the bounds separately. So the old code(see the comments below) is sufficient but now the returned array is empty which could mean that this is a bug in itself.


Annotation [] [com.test.IntersectionType.Test]
Annotation [[]] [java.lang.String&java.io.Serializable]
Annotation [[]] [java.lang.String]
Annotation [[]] [java.io.Serializable]


public class IntersectionType {

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.TYPE_USE)
    public @interface TypeUses {
        TypeUse[] value();
    }

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.TYPE_USE)
    @Repeatable(TypeUses.class)
    protected @interface  TypeUse {
        int value();
    }

    //Intersection type
    class Test<T extends String & @IntersectionType.TypeUse(value = 2) Serializable>{

    }
}

Processor method


    private void processClassTypeParameters(Element e) {


        for (TypeParameterElement typeParameterElement : ((TypeElement) e).getTypeParameters()) {

            for( AnnotationMirror am  : typeParameterElement.getAnnotationMirrors() ){

                System.out.println( "Annotation [" + am + "] [" + typeParameterElement  + "]");


            }
            //Get the intersection type
            TypeVariable tv = (TypeVariable)typeParameterElement.asType();

            TypeMirror tm = tv.getUpperBound();
            //This may not return anything.(See explanation above)
            System.out.println( "Annotation [" + Arrays.asList( tm.getAnnotationsByType(com.test.IntersectionType.TypeUse.class)) + "] [" + tm  + "]");

            for (TypeMirror typeMirror : typeParameterElement.getBounds()) {
                //Commented section is not the right way
                //if( typeMirror instanceof javax.lang.model.type.IntersectionType) {

                //The following line returns an empty array most probably due to a different bug.
                    System.out.println( "Annotation [" + Arrays.asList(typeMirror.getAnnotationsByType(com.test.IntersectionType.TypeUse.class)) + "] [" + typeMirror  + "]");

                //}
            }
        }
    }

Repeatable Annotations

It looks like the annotations can repeat according to Repeating Annotations.

I am still using

java version "1.8.0-ea"
Java(TM) SE Runtime Environment (build 1.8.0-ea-b113)
Java HotSpot(TM) 64-Bit Server VM (build 25.0-b55, mixed mode)

This code has a problem.

  1. Arrays.asList(typeMirror.getAnnotationsByType(RepeatableAnnotation.TypeUse.class))

    This does not print anything. There are two annotations.

This could be a problem with the particular JDK 8 build. The latest is b120. I have to try the latest build.

Update: This is most likely a code problem because even b120 does not help.

Update 1: This is not a code problem but b120 has some bugs according to the type-annotations-dev list.

The result is this.


Annotation [@com.test.RepeatableAnnotation.TypeUses({@com.test.RepeatableAnnotation.TypeUse(0), @com.test.RepeatableAnnotation.TypeUse(1)})] [com.test.RepeatableAnnotation.Test1]
[value()][{@com.test.RepeatableAnnotation.TypeUse(0), @com.test.RepeatableAnnotation.TypeUse(1)}]
Annotation [[]] [java.lang.Integer]

I am not able to get the annotations applied on the bound Integer

package com.test;

import java.lang.annotation.*;

public class RepeatableAnnotation {

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.TYPE_USE)
    public @interface TypeUses {
        TypeUse[] value();
    }

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.TYPE_USE)
    @Repeatable(value = TypeUses.class)
    protected @interface  TypeUse {
        int value();
    }

    @TypeUse(value = 0) @TypeUse(value = 1)class Test1< T extends @TypeUse(value = 2) @TypeUse(value = 3) Integer> {

        /**
         * A type annotation is permitted in front of a constructor declaration, where declaration annotations are already
         permitted.
         */
        @TypeUse(value = 0) <S> Test1(String s){

        }
    }

}

Annotation Processor


package com.test;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.*;
import javax.lang.model.type.ExecutableType;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.type.TypeVisitor;
import javax.lang.model.util.SimpleTypeVisitor8;
import java.util.*;

import static javax.lang.model.util.ElementFilter.typesIn;

@SupportedAnnotationTypes("*")
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class RepeatableAnnotationFinder extends AbstractProcessor{


    public RepeatableAnnotationFinder(){
        super();
    }

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {

        TypeElement tye = null;

        if( !roundEnv.processingOver()){

            Iterator<? extends Element> te = annotations.iterator();

            for (TypeElement element : typesIn(roundEnv.getRootElements()) ) {

                processEnclosedElements(element.getEnclosedElements(),
                                        roundEnv);

            }
        }
        return false;
    }

    private void processEnclosedElements(List<? extends Element> enclosedElements,
                                         RoundEnvironment roundEnv) {

        for( Element e : enclosedElements ){

            if (e.getKind() == ElementKind.CLASS){

                System.out.println( "Annotation [" + e.getAnnotationMirrors() + "] [" + e  + "]");

                processClassTypeParameters(e);
            }
        }
    }

    private void processClassTypeParameters(Element e) {

        for (TypeParameterElement typeParameterElement : ((TypeElement) e).getTypeParameters()) {

            for( AnnotationMirror am  : typeParameterElement.getAnnotationMirrors() ){

                System.out.println( "Annotation [" + am + "] [" + typeParameterElement  + "]");

                for(Map.Entry< ? extends ExecutableElement, ? extends AnnotationValue> m : am.getElementValues().entrySet()){

                    System.out.println( "[" + m.getKey() +"][" + m.getValue() + "]");

                }

            }

            for (TypeMirror typeMirror : typeParameterElement.getBounds()) {

                System.out.println( "Annotation [" + Arrays.asList(typeMirror.getAnnotationsByType(RepeatableAnnotation.TypeUse.class)) + "] [" + typeMirror  + "]");

            }
        }
    }
}

So I will wait for a newer build before trying this again.

Annotation Processors

Lambdas are very popular now. But I realized I haven’t used the annotation processor API since JSE 5. None of the projects I came across has even used good generics. So even JSE 5 is not properly used.

I just compiled and executed this. It is not complete because I am trying to print all the annotations actually used in the code shown(Test.java) in my previous blog entry.

I am using

java version "1.8.0-ea"
Java(TM) SE Runtime Environment (build 1.8.0-ea-b113)
Java HotSpot(TM) 64-Bit Server VM (build 25.0-b55, mixed mode)

Now it is printing this.

Annotation [com.test.Test.TypeUse] [[com.test.Test.Test1]]
Annotation [com.test.Test.TypeParameter] [[T, S]]
Annotation [com.test.Test.TestTypeParameter] [[T, S]]
Annotation [@com.test.Test.TypeUse] [com.test.Test.Test1]
Annotation [] [java.lang.Integer]
Annotation [@com.test.Test.NonNull] [argv]

I will update the code later once I manage to fix it.

Update : Now it is printing this. Code is updated. I will explain the changes.

Annotation [com.test.Test.TypeParameter] [[T, S]]
Annotation [com.test.Test.TestTypeParameter] [[T, S]]
Annotation [@com.test.TypeUse] [com.test.Test.Test1]
Annotation [[Lcom.test.TypeUse;@2a5ca609] [java.lang.Integer]
Annotation [@com.test.Test.NonNull] [argv]
-> (java.lang.String[])void

Change 1

This method which I used earlier turns the TypeMirror back to a DeclaredType. That is not required.

    private void processClassTypeParameters(Element e) {
        for (TypeParameterElement typeParameterElement : ((TypeElement) e).getTypeParameters()) {
            //System.out.println( &quot;Annotation [&quot; + typeParameterElement.getAnnotationMirrors() + &quot;] [&quot; + typeParameterElement  + &quot;]&quot;);
            for (TypeMirror typeMirror : typeParameterElement.getBounds()) {
                System.out.println( &quot;Annotation [&quot; + ((DeclaredType)typeMirror).getAnnotationMirrors() + &quot;] [&quot; + typeMirror  + &quot;]&quot;);
            }
        }
    }

This method is replaced with the new method in Test.java shown below. typeMirror.getAnnotationsByType(TypeUse.class) is sufficient to get the annotation on Integer

Change 2

I introduced a new method to get the annotations inside a method and source on which they are applied. But that is not possible. Alex Buckley, the JSR 308 spec. lead replied that

There is no access to annotations in a method body from the Language Model API (or the Core Reflection API).

Actually I introduced this method and called it like this e.asType().accept(visitor(),null); to try to get the annotations from inside the method. This is the method that is printing

    -> (java.lang.String[])void

    private TypeVisitor<Boolean, Void> visitor() {
        return new SimpleTypeVisitor<Boolean, Void>() {
            public Boolean visitExecutable(ExecutableType t, Void v) {
                System.out.println("-> " + t);
                return true;
            }
        };
    }


AnnotationFinder.java

package com.test;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.*;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.ExecutableType;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.type.TypeVisitor;
import javax.lang.model.util.ElementFilter;
import javax.lang.model.util.SimpleTypeVisitor6;
import javax.lang.model.util.SimpleTypeVisitor8;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import static javax.lang.model.util.ElementFilter.typesIn;

@SupportedAnnotationTypes("*")
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class AnnotationFinder extends AbstractProcessor{


    public AnnotationFinder(){
        super();
    }

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {

        TypeElement tye = null;

        if( !roundEnv.processingOver()){

            Iterator<? extends Element> te = annotations.iterator();

            for (TypeElement element : typesIn(roundEnv.getRootElements()) ) {

                processEnclosedElements(element.getEnclosedElements(),
                                        roundEnv);

            }
        }
        return false;
    }

    private void processEnclosedElements(List<? extends Element> enclosedElements,
                                         RoundEnvironment roundEnv) {

        for( Element e : enclosedElements ){

            if( e.getKind() == ElementKind.ANNOTATION_TYPE &&

                    !roundEnv.getElementsAnnotatedWith((TypeElement) e).isEmpty()){

                System.out.println( "Annotation [" + e + "] [" +
                        roundEnv.getElementsAnnotatedWith((TypeElement) e) + "]");

            }else if( e.getKind() == ElementKind.METHOD ){

                for (VariableElement variableElement : ((ExecutableElement) e).getParameters()) {

                    System.out.println("Annotation [" + variableElement.getAnnotationMirrors() + "] [" +

                                                                                         variableElement + "]");
                    e.asType().accept(visitor(),null);

                }

            }else if (e.getKind() == ElementKind.CLASS){

                System.out.println( "Annotation [" + e.getAnnotationMirrors() + "] [" + e  + "]");

                processClassTypeParameters(e);
            }
        }
    }

    private TypeVisitor<Boolean, Void> visitor() {

        return new SimpleTypeVisitor8<Boolean, Void>() {

            public Boolean visitExecutable(ExecutableType t, Void v) {

                System.out.println("-> " + t);

                return true;
            }
        };
    }

    private void processClassTypeParameters(Element e) {

        for (TypeParameterElement typeParameterElement : ((TypeElement) e).getTypeParameters()) {

            //System.out.println( "Annotation [" + typeParameterElement.getAnnotationMirrors() + "] [" + typeParameterElement  + "]");

            for (TypeMirror typeMirror : typeParameterElement.getBounds()) {

                System.out.println( "Annotation [" + typeMirror.getAnnotationsByType(Test.TypeUse.class) + "] [" + typeMirror  + "]");

            }
        }
    }
}

JSR 308

The annotation system has been extended. I realized that there are more annotation types and more source locations where they are permitted.

I compiled a simple example. The specification is here

java version "1.8.0-ea"
Java(TM) SE Runtime Environment (build 1.8.0-ea-b113)
Java HotSpot(TM) 64-Bit Server VM (build 25.0-b55, mixed mode)


package com.test;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;


public class Test {

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.TYPE_USE)
    @interface  TypeUse {}

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.TYPE_PARAMETER)
    @interface  TypeParameter {}

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.TYPE_PARAMETER)
    @interface  TestTypeParameter {}

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.PARAMETER)
    @interface NonNull {}


    /**
             * ElementType.TYPE PARAMETER stands for a type parameter — that is, the declaration of a type variable. Examples
             are in generic class declarations class MyClass<T> {...}, generic method declarations <T> foo(...) {...}, and
             wildcards List<?>, which declare an anonymous type variable.
             * @param <T>
             */
    @TypeUse class Test1<@TypeParameter @TestTypeParameter T extends @TypeUse Integer> {

        /**
         * A type annotation is permitted in front of a constructor declaration, where declaration annotations are already
         permitted.
         */
        @TypeUse <@TypeParameter @TestTypeParameter S> Test1(String s){

        }
    }


    public static void main(  @NonNull String... argv ){

        Object o = ( @TypeUse String ) new String( "Test" );

        if( o instanceof @TypeUse String ){

        }
        try{

        }catch( @NonNull Exception e){

        }

    }
}
        List list1 = list.
                       stream().
                        map(p::matcher).
                          filter(Matcher::find).map(matcher -> matcher.group()).
                              collect(Collectors.toCollection(@ NonNull ArrayList::new));

Simplified code using Java 8 flatMap

This code solved one of the problems. It accumulates all the matches by looping over m.find(). The main problem is still not solved. It does not work on the result of the previous match.

So the result is wrong.

[Current Usage : init:2359296, used:13913536, committed:13959168, max:50331648|]
[Current Usage : init:2359296, used:13915200, committed:13959168, max:50331648|]
[2359296, 13914944, 13959168, 50331648, 2359296, 13913536, 13959168, 50331648, 13, 31, 48, 13, 27]
[2359296, 13916608, 13959168, 50331648, 2359296, 13915200, 13959168, 50331648, 13, 31, 48, 13, 27]

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


public class SimplerFlatMapTest {

    public static void main( String... argv ){

        List<String> source = new ArrayList<String>();
        source.add( "Peak Usage    : init:2359296, used:13914944, committed:13959168, max:50331648Current Usage : init:2359296, used:13913536, committed:13959168, max:50331648|------------------| committed:13.31Mb+---------------------------------------------------------------------+|//////////////////|                                                  | max:48Mb+---------------------------------------------------------------------+|------------------| used:13.27Mb");
        source.add( "Peak Usage    : init:2359296, used:13916608, committed:13959168, max:50331648Current Usage : init:2359296, used:13915200, committed:13959168, max:50331648|------------------| committed:13.31Mb+---------------------------------------------------------------------+|//////////////////|                                                  | max:48Mb+---------------------------------------------------------------------+|------------------| used:13.27Mb");

        List<Pattern> patterns = Arrays.asList(Pattern.compile("Current.*?[/|]"), Pattern.compile("[0-9]+(/,|/|)"));


        Function<Matcher, List<String>> matches1 = m -> {
            List<String> list = new ArrayList<String>();
            while(m.find()) {
                list.add(m.group());
            }
            return list;
        };

        patterns.stream()
                .flatMap(p -> source.stream().map(p::matcher))
                .map(matches1)
        .forEach(System.out::println);
    }
}

Java 8 flatMap

I compiled this code with

java version "1.8.0-ea"
Java(TM) SE Runtime Environment (build 1.8.0-ea-b113)
Java HotSpot(TM) 64-Bit Server VM (build 25.0-b55, mixed mode)

The documentation of flatMap was not easy to understand but there are two streams that are mixed – the source stream and the regular expression pattern stream. I am applying the regular expressions one by one on the source lines to get what I want. So here I am able to get the first value(2359296) from the line

The problem with this approach is this. The result of the first regex match is this line.

Current Usage : init:2359296, used:13913536, committed:13959168, max:50331648|

The second regex should be applied on this line. Not on the original line. But that is how this code works. Moreover it does not give me all the values returned by looping over Matcher::find

Not the other values. I have to find a way of coding it to get all.


import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class FlatMapTest {

    public static void main( String... argv ){

        List<String> source = new ArrayList<String>();
        source.add( "Peak Usage    : init:2359296, used:13914944, committed:13959168, max:50331648Current Usage : init:2359296, used:13913536, committed:13959168, max:50331648|------------------| committed:13.31Mb+---------------------------------------------------------------------+|//////////////////|                                                  | max:48Mb+---------------------------------------------------------------------+|------------------| used:13.27Mb");
        source.add( "Peak Usage    : init:2359296, used:13916608, committed:13959168, max:50331648Current Usage : init:2359296, used:13915200, committed:13959168, max:50331648|------------------| committed:13.31Mb+---------------------------------------------------------------------+|//////////////////|                                                  | max:48Mb+---------------------------------------------------------------------+|------------------| used:13.27Mb");

        List<Pattern> patterns = Arrays.asList(Pattern.compile("Current.*?[/|]"), Pattern.compile("[0-9]+(/,|/|)"));

        //Style 1
        patterns.stream()
                .flatMap(new Function<Pattern, Stream<String>>() {
                    @Override
                    public Stream<String> apply(Pattern p) {
                        return source.stream()
                                .map(p::matcher)
                                .filter(Matcher::find)
                                .map(Matcher::group);
                    }
                })
                .forEach(System.out::println);

        //Style 2
        patterns.stream().flatMap(( Pattern p1 ) -> source.
                stream().
                map(p1::matcher).
                filter(Matcher::find).map(matcher -> matcher.group())).forEach(x -> System.out.println(x));

    }
}

Learning Lambda

I think Java lambdas have some powerful functional programming support and this is an attempt to convert part of the ‘R’ code to Java.

I start with this line from the GC log file.

Total Memory Pools: 5

Pool: Code Cache (Non-heap memory)

Peak Usage : init:2359296, used:13914944, committed:13959168, max:50331648
Current Usage : init:2359296, used:13913536, committed:13959168, max:50331648

|------------------| committed:13.31Mb
+---------------------------------------------------------------------+
|//////////////////| | max:48Mb
+---------------------------------------------------------------------+
|------------------| used:13.27Mb

Pool: PS Eden Space (Heap memory)

Peak Usage : init:89522176, used:186449920, committed:234356736, max:234618880
Current Usage : init:89522176, used:36258088, committed:233570304, max:233635840

|--------------------------------------------------------------------| committed:222.75Mb
+---------------------------------------------------------------------+
|////////// || max:222.81Mb
+---------------------------------------------------------------------+
|---------| used:34.58Mb

Pool: PS Survivor Space (Heap memory)

Peak Usage : init:14876672, used:25217592, committed:35651584, max:35651584
Current Usage : init:14876672, used:0, committed:1114112, max:1114112

|---------------------------------------------------------------------| committed:1.06Mb
+---------------------------------------------------------------------+
| | max:1.06Mb
+---------------------------------------------------------------------+
| used:0b

Pool: PS Old Gen (Heap memory)

Peak Usage : init:954466304, used:272270080, committed:954466304, max:1886519296
Current Usage : init:954466304, used:269639088, committed:954466304, max:1886519296

|----------------------------------| committed:910.25Mb
+---------------------------------------------------------------------+
|////////// | | max:1.76Gb
+---------------------------------------------------------------------+
|---------| used:257.15Mb

Pool: PS Perm Gen (Non-heap memory)

Peak Usage : init:16777216, used:112329944, committed:210763776, max:1073741824
Current Usage : init:16777216, used:112329944, committed:112852992, max:1073741824

|------| committed:107.62Mb
+---------------------------------------------------------------------+
|//////| | max:1Gb
+---------------------------------------------------------------------+
|------| used:107.13Mb

tables <- htmlParse("memorypools.txt")

y <- xpathSApply(tables,"//b//text()[contains(.,'Pool: Code Cache')]//following::blockquote[1]",xmlValue)
y <- data.frame(y)

I use ‘R’ to parse the line first because I found it hard to use Java to parse the unstructured line with HTML tags

After the first phase the line looks like this.

[1] "Peak Usage : init:2359296, used:13914944, committed:13959168, max:50331648Current Usage : init:2359296, used:13913536, committed:13959168, max:50331648|------------------| committed:13.31Mb+---------------------------------------------------------------------+|//////////////////| | max:48Mb+---------------------------------------------------------------------+|------------------| used:13.27Mb"

Java 8 code

import java.io.IOException;
import java.nio.file.Files;
import java.util.Scanner;
import java.util.stream.Stream;

import static java.nio.charset.StandardCharsets.UTF_8;
import static java.nio.file.Paths.get;

public class GCLogParser {

    private void readFile() throws IOException {

        Stream<String> s = Files.lines(get("gclog.txt"), UTF_8);
        s.forEach( this::parse  );
    }

    public static void parseDocument(Parseable parser,
                                     String data){
        parser.apply(data);
    }
    private void parse( String data ){

        Scanner s = new Scanner( data );
        s.findInLine("Current.*?[/|]");
        System.out.println(s.match().group());
    }

    public static void main( String... argv ) throws IOException {
        new GCLogParser().readFile();
    }

    @FunctionalInterface
    public interface Parseable{
         void apply( String s);
    }
}

This Java code gives me this line. This is just new syntax and constrcts and I don’t think I have used the functional style of programming properly here.

Current Usage : init:2359296, used:15775680, committed:15859712, max:50331648|

Direct Web Remoting

I believe in change but applications developed by our companies do not use technology in adequate measure. They do not change with the times. This is caused by fear of software. Software breaks in production and if we have inadequate unit tests we are scared.

I have written a simple test using DWR several years back but I haven’t used it anywhere. DWR enables us to communicate with our browsers using Ajax in the reverse. I experimented with it again and this code updates the ‘div’ in the browser at periodic intervals.

The code is not written very well but it works. There are techniques to shutdown the threads properly.

The main purpose is to detect broken links to the browser and expire the sessions. That is a hard problem now.

I will add details if I am able to achieve it.


package com.test;

import java.util.Collection;
import java.util.Iterator;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

import org.directwebremoting.Browser;
import org.directwebremoting.Container;
import org.directwebremoting.ScriptSession;
import org.directwebremoting.ServerContextFactory;
import org.directwebremoting.extend.ScriptSessionManager;
import org.directwebremoting.ui.dwr.Util;

public class ReversePublisher {

	ScheduledExecutorService scheduledExecutorService =
	        Executors.newScheduledThreadPool(5);

	    public void publish(){
	    		    	
	    	@SuppressWarnings("unchecked")
			ScheduledFuture<?> scheduledFuture =
	    	    scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
	    	        public void run() {
	    	        	setDiv();
	    	        }
	    	    },
	    	    5,
	    	    5,
	    	    TimeUnit.SECONDS);

	    }

	    /**
	     * Update using reverse Ajax
	     */
	    public void setDiv(){
	    	try{

	    		Browser.withAllSessions(new Runnable()
	    		{
		    		public void run(){ 
		    	    	try{
		    	    		Util.setValue("Timeout", "Reverse Ajax"); 
		    	    	}catch(Exception e){
		    		    	System.out.println( "Detecting broken link " + e.getMessage());
		    	 	   	}
		    		}
	    		});		        
	    	}catch(Exception e){
		    	System.out.println( "Exception in Publishing in the reverse " + e.getMessage());
	 	   	}
	    }
}

Update

After asking the DWR forum I understood that when I enable ‘Reverse Ajax’ in web.xml there is an implicit polling call being made by the browser. Mike Wilson answered my questions sent to the DWR user list. This particular problem does not require a scheduled Thread to make frequent polling calls to the browser. It is implicit.

This call is made at a certain configurable interval regularly. I coded a filter to trap this call and stored the access times. If a browser crashes or closes these calls are not made for a specific period. When the browser opens again, even if cookies or caches are reinstated this filter can check the last accessed time and the current time and decide to expire the HttpSession.

I believe at this time that can solve my problem. Network latency could cause concerns though.

Google Chrome’s JavaScript console shows this implicit polling call.

reverseajax

IntelliJ IDEA anonymous class as Java 8 lambda

I recently started coding lambdas. This is partly to prevent my Java skills from getting rusted.

I found that IntelliJ IDEA has this interesting feature that allows an inner class to be shown as a lambda.

 public class Employee {

           public Employee( String name,int age){
               this.age = age;}

           interface CheckAge {boolean test(Employee p);
                 int age;
                 public int getAge() {
                       return 36;
                 }
 
           static void printEmployees( List<Employee> m, CheckAge ca ){
             for( Employee m1 : m ){
                System.out.println( ca.test( m1 ));
             } 
           }

           public static void main( String... argv ){

                List<Employee> employees= new ArrayList<Employee>();

                employees.add( new Employee( "Test", 29));

                printEmployees( employees,new CheckAge() {
                     public boolean test(Employee p) {
                         return p.getAge() >= 18;
                                  p.getAge() <= 35;}
                });
   }
 }


Lambda

The printEmployees method has an anonymous inner class and the screenshot shows
IntelliJ IDEA’s interpretation.

The product company I am working for is very far behind this type of technology curve and only technology evangelism might help.