This blog is about Java (advanced Java topics like Reflection, Byte Code transformation, Code Generation), Maven, Web technologies, Raspberry Pi and IT in general.

Sonntag, 31. Mai 2015

spBee - Stored Procedure Bee: a database framework


The Background Story
At work we use only stored procedures to access the database. First I was quite skeptical. Why don't we use JAP/Hibernate? But there are some reasons for that:
  • Performance
  • It's very easy. Three other projects at work are using Hibernate. All of them had to fight with performance issues. It's quite complicate to make Hibernate work efficiently.
  • It's the interface to the database. As a developer I don't care about the database tables. I just want the data I am interested in and the stored procedures give me the data in a very easy way.
There are more reasons for and against them. But actually I don't want to discuss this in greater detail.

The Problem
One thing that always bothered me with our stored procedure implementation was the necessity to map the Resultset manually. It looks like this but with more fields/columns:

Pojo pojo = new Pojo();
pojo.setId(theResultSet.getInt(1));
pojo.setName(theResultSet.getString(2));
pojo.setEnum(SomeEnum.fromId(theResultSet.getInt(3)));
return pojo;

I wanted a more elegant solution. So I spent some of my free time to figure out a solution. The solution I wanted should be very easy to use and the implementation should be easy, too. Nowadays many things rely on in-memory-code-generation and reflection. But the problem with that is that it's impossible to debug. Furthermore it's not easy to implement.

The Solution: spBee - how it works
That is why I decided to generate Java code. It's easy to create Java code with JCodeModel and it gives you the opportunity to debug the code. The code is generated based on the structure of the Java classes and on some Java annotations. To make the integration smooth everything is done in the Pre-Compile-Phase. Since Java 1.6 it's possible to hook up an annotation processor before the code is compiled. In this step it's possible to generate Java code. The generated Java code will be compiled to byte code together with the rest of the code. With Maven it's very easy to configure the annotation processor. So every time you build the project the boring to write code will be generated automatically.

The current implementation depends heavily on Spring. The first dependency to Spring is that the StoredProcedure from Spring is used - because of that it saved me to write more code. The second dependency to Spring is that it builds on top of the Dependency Injection of Spring. This has the benefit that the source code is always clean. Because in the code only the interfaces are used. The implementation of the interfaces, which will be generated by spBee, will be wired up correctly by Spring at runtime.

Example

@Entity 
public class User {  
  private int id;
  private String name;

  private User() {}

  @MappingConstructor
  public User(int id, String name) {
     this(id, name);   
  }

  public int getId() { return id; }

  public String getName() { return name; } 
}

@Dao 
public interface UserDao {  
  // list of entities  
  @StoredProcedure("sp_get_users")  
  List getUsers();

  // single entity  
  @StoredProcedure("sp_get_user")
  public User getUser(int id); 
}

// execution
@Autowired UserDao userDao; 
List users = userDao.getUsers(); 
User user = userDao.getUser(1)

Explanation of the example
The UserDao interface just groups together all stored procedures which are related to the user. The interface has two methods which call two different stored procedures. The name of the stored procedure is declared within the @StoredProcedure annotation. The getUsers() method will just call the sp_ger_users stored procedures without any parameters. Then the result is mapped into a list of User entities. How does spBee know how to map the result? It just reads the @MappingConstrutor, looks at the types of the parameters and generates the corresponding code. It's possible to have several @MappingConstructors - you just have to give them names. Actually, that's it! The getUser() method will call the stored procedure with one int value. The list is automatically unpacked into a single element. If there is not exactly one row returned from the database then an exception is thrown. But you can configure it so that it returns null. Or you could wrap it into an Optional type.
There are more features like multiple result sets and so on. If you are interested then please take a look at the spBee documentation.

Conclusion
For me it was fun to write this framework. I believe that the framework is stable and others can benefit from it, too. Furthermore take a look at the SPBeeAnnotationProcessor. It's a very powerful but quite unknown feature of Java. In combination with Dependency Injection it integrates very well. That's because nowhere in your code you are using the generated code - no errors occur, if the code wasn't generated yet. Just one warning: it's a little bit troublesome to write an annotation processor and you can't use reflection at this point. You need to read the code with the help of the AST API.
Nevertheless it's great fun and it's awesome if it works in the end!

Samstag, 14. März 2015

Tutorial: How to push / upload artifacts into the Maven Central Repository

I have several GitHub repositories and that's great. It's so easy to share the projects. But for some projects it's not enough. I created a POM, which I'm using as parent POM for all my projects. So if you want to checkout a project which depends on the POM then it's necessary to checkout the pom-project first and do a $ mvn install. That's quite annoying. The second example is my spBee library. I think most users aren't interested to checkout that project and to contribute to it - they just want to use it. Therefore it's necessary in such cases to put the artifacts on the Maven Central Repository. Then the user can add the library to the Maven dependencies and everything works. So I faced the question: how to push my artifacts to the Maven Central Repository?

A short overview over all steps
  1. install PGP - that's necessary to sign the artifacts - and upload your public key 
  2. prepare the POM file to satisfy all requirements
  3. create an Sonatype account
  4. create a New Project ticket
  5. wait for a comment.
  6. perform a stating release and comment the ticket that you have successfully done the stating release and the artifacts are ready to be released.
  7. wait until the sync to the Maven Central Repository will be activated and now you can do the releases yourself.
    1. do another staging release
    2. release your artifacts on this site https://oss.sonatype.org/
    3. or drop your staging release
  8. enjoy your artifacts on the Maven Central Repository
It seems to be quite complicated. But actually it's not that bad. Hopefully it's very easy with the help of this post!

1. Install PGP and upload your public key
 On this site everything is explained. In short:
  • download and install GPG
  • $ gpg --version
  • $ gpg --gen-key
    • enter the required information
  • $ gpg --list-keys
    • in the output you will see the keyid of the public certificate
    • pub   1024D/C6EED57A 2010-01-13
    • the C6EED57A string is the keyid
  • distribute the public key so that the signed files can be verified
    • $ gpg --keyserver hkp://pool.sks-keyservers.net --send-keys C6EED57A
2. Prepare the POM file to satisfy all requirements
On this site and that site everything is explained. In short:
  • the groupId
    • if the groupId is at.rseiler.spbee then you need to own rseiler.at.
    • if you don't have an own domain, but use GitHub then the groupId must be: github.com/rseiler => com.github.rseiler
  • the javadoc.jar must be generated
  • the sources.jar must be generated
  • all files must be signed with PGP
  • following meta data must be provided
    • project name, description and URL
    • license information
    • developer information 
    • scm (the repository URL)
  • the nexus-staging-maven-plugin must be setup
  • the distributionManagement (snapshotRepository and
    repository) must be setup
Take a look at these both small POM files, which satisfies all requirements: spBee POM pom-project POM
The  release profile will create the javadoc.jar sources.jar and signs the artifacts. So if you do a release you need to activate the profile with: $ mvn clean deploy -P release

To upload the artifacts you need to setup the settings.xml (.m2/settings.xml).
<settings>
  <servers>
    <server>
      <id>ossrh</id>
      <username>your-jira-id</username>
      <password>your-jira-pwd</password>
    </server>
  </servers>
</settings>
3. Create an Sonatype account
Go to this site and create an account.

4. Create a New Project ticket
  • go to this site and create a ticket - see mine as an example
  • enter the root groupId
    • at.rseiler - even if your first artifact uses at.rseiler as groupId
    • com.github.rseiler - if you don't have an own domain
  • fill out the rest of the fields
6. Preform a stating release
  • check if everything is setup correctly
  • I recommend to set <autoReleaseAfterClose>true</autoReleaseAfterClose> to false so you can check the output first
  • notice that there aren't allowed any JavaDoc errors. If there are errors than the javadoc.jar file won't be created and then the requirements are missed.
  • $ mvn clean deploy -P release
  • check on this site under Build Promation => Repositories => Content your uploaded artifacts
  • if everything is fine then use: $ mvn nexus-staging:release to do a stating release
  • otherwise $ mvn nexus-staging:drop to drop the stating release
  • both commands can be executed on the website, too
  • comment the ticket
7. Release yourself
After the sync is activated you can release your stating-releases yourself to the Maven Central Repository.

8. Enjoy your artifacts on the Maven Central Repository 
You have done it! Congratulation! :)


I hope that my blog post helped you and gave you a good overview over all required steps.

Montag, 16. Februar 2015

Publish Maven Site Documentation automatically to the GitHub Pages


Maven site is a great tool as well as GitHub. The coolest thing about those tools is that they play together very well. Only a little Maven configuration is needed. But let me explain shortly what both tools do.

Maven Site: generates automatically a nice documentation website for your Maven project. Many Apache projects uses this generated site as their main website. So probably you have already seen such generated websites. An nice example is the my (parent) POM project or the maven-site-plugin. Mainly the documentation consists of three parts:
  • Project information like dependencies, license, source repository and so on. 
  • Project reports like unit tests reports, static code analysis reports, JavaDocs and so on. 
  • The documentation written by the developers. With an additional Maven Plugin it's possible to write the documentation with Markdown.
GitHub Pages: GitHub doesn't only provide a GIT repository but also can be used as webhost for static website. Which is ideal for a project website. The GitHub Pages concept is very cool. It's just a branch, called gh-pages, in you project repository. All the files that are pushed into this branch will be served from GitHub`s webserver. An nice example is the documentation for my (parent) POM project.
Before you start with the Maven configuration you should read Creating Project Pages manually for a better understanding.


Before we can start with the GitHub Pages integration into Maven we firstly need to correctly build the website. For multi module projects it's necessary to deploy (locally is sufficient) the website first. Otherwise the references between modules won't work. To do so you just need to configure the distribution management like this:

<distributionManagement>
<site>
<id>site-docs</id>
<url>file://${env.HOME}/sitedocs/pom-project</url>
</site>
</distributionManagement>

How to fully configure the generation of the Maven Site is too much for this blog post. Look at the POM for some good basic configuration or just us it as parent POM for your project. The minimum of configuration is:

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-site-plugin</artifactId>
            <version>3.4</version>
            <executions>
                <!-- used for multiproject builds -->
                <execution>
                    <id>attach-descriptor</id>
                    <goals>
                        <goal>attach-descriptor</goal>
                    </goals>
                </execution>
            </executions>
            <dependencies>
                <!-- To use the Markdown format -->
                <dependency>
                    <groupId>org.apache.maven.doxia</groupId>
                    <artifactId>doxia-module-markdown</artifactId>
                    <version>1.6</version>
                </dependency>
            </dependencies>
        </plugin>
    </plugins>
</build>

<reporting>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-project-info-reports-plugin</artifactId>
            <version>2.7</version>
            <configuration>
                <dependencyLocationsEnabled>false</dependencyLocationsEnabled>
            </configuration>
            <reportSets>
                <reportSet>
                    <reports>
                        <report>index</report>
                        <!--<report>cim</report>-->
                        <report>dependencies</report>
                        <!--<report>dependency-convergence</report>-->
                        <report>dependency-info</report>
                        <report>dependency-management</report>
                        <!--<report>distribution-management</report>-->
                        <!--<report>issue-tracking</report>-->
                        <report>license</report>
                        <!--<report>mailing-list</report>-->
                        <report>modules</report>
                        <report>plugin-management</report>
                        <report>project-team</report>
                        <report>scm</report>
                        <report>summary</report>
                    </reports>
                </reportSet>
            </reportSets>
        </plugin>
    </plugins>
</reporting>

To build the Maven Site just use: mvn clean site site:deploy
The integration into the GitHub pages is very easy and looks like this:

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-scm-publish-plugin</artifactId>
            <version>1.1</version>
            <inherited>true</inherited>
            <configuration>
                <checkoutDirectory>${project.basedir}/github.com</checkoutDirectory>
                <checkinComment>publishing site documentation</checkinComment>
                <content>${env.HOME}/sitedocs/pom-project</content>
                <pubScmUrl>scm:git:https://github.com/rseiler/pom-project.git</pubScmUrl>
                <scmBranch>gh-pages</scmBranch>
            </configuration>
        </plugin>
    </plugins>
</build>

Additional you need to configure your username and password in the .m2/settings.xml. It should look like this:

<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
                      http://maven.apache.org/xsd/settings-1.0.0.xsd">
  <servers>
    <server>
      <id>github.com</id>
      <username>github-username</username>
      <password>github-password</password>
    </server>
  </servers>
</settings>

If everything is done just type: 

mvn clean site site:deploy scm-publish:publish-scm -Dscmpublish.dryRun=true

The scmpublish.dryRun flag prevents the plugin to commit anything and just outputs what changes it would commit. Check it and if everything works than rerun the command without this flag: 

mvn clean site site:deploy scm-publish:publish-scm

That's it! It's Very simple :)

Samstag, 6. September 2014

Class Transformation with ASM

Have you ever asked yourself how class transformation works? Great, then you are reading the right blog post ;-)

Probably not everybody knows what class transformation is. Therefore I will start to explain it before I will explain how it works. 

What is class transformation?

Actually it's there is a quite simple answer to this question: the Java bytecode will be modified in some kind. But let me explain it more detailed. If you compile a Java file a class file will be generated. The class file represents the Java source file as Java binary code. So it's much smaller and optimized for execution. The methods consists of the Java opcodes. These opcodes will pushed sequentially onto the Java stack and will be executed. Class transformation means that the Java byte code, which represents a Java class, will be modified. So opcodes can be inserted or removed. But not only the opcodes inside of a method can be modified. Everything can be changed - any program can be transformed in anything else! At least as it is still valid Java byte code. Otherwise the Java Bytecode Verifier will reject the class if the class will be loaded.

Where is class transformation used?

Why would you transform a class if you just could write the Java class like you need it to be? Actually if you can accomplish your work without class transformation than don't use class transformation. Just write the Java code accordingly. I think the most commonly usage of class transformation is to instrument Java code at runtime. Imagine if you have a big program which has performance problems and there are no performance tools like VisualVM or JProfiler. What would you do to find the methods which takes long to execute?
You would have to insert at each method the code to measure the execution duration of the method. If there are thousands of methods this would be a quite boring work. E
specially since you need to remove the code for the production code and probably add it again to do the analyze the execution durations again. With class transformation you can do exactly this boring work. You don't write the duration measurement code in you Java files. But you read the existing class file and insert the needed opcodes to each class, to each method.
Actually all performance tools work like this. Java allows to modify already loaded classes, with some restrictions, too. So these tools gets the binary code of the classes, rewrites the classes on a binary level and Java loads the modified classes. Than the tools can generate analysis and pretty diagrams from the instrumented classes.

ASM

ASM is a great library which allows to transform classes. It consists of three main parts
  •  ClassReader: reads a binary class
  • ClassWriter: writes a binary class
  • ClassVisitor: transforms the binary class by calling the visit-methods of your implementation
To be able to create class transformations you need to understand the Java opcodes and how a stack based language works. At least you need a rudimentary understanding.

There are tools which will show you the byte code of any class and generate the ASM code to create this class with ASM. Therefore you don't need to write all the opcodes by hand. Just write a Java class which should be the result of your transformation. Than look at the generated code and adapt it to your needs. In theory that sounds very easy. But at least I had to read the ASM documentation and the Java opcodes documentation, too. To make a quite simple transformation work. 

 Example

This example, which can be found completely on GitHub, does two things.
  • Wraps all static Logger variables
  • Logs all method calls
For more details read the code. It's heavily documented and it makes more sense to read than anything else. Have fun! :-)

The code on GitHub with syntax hilighting, yeah: https://github.com/rseiler/concept-class-transformation-with-asm/blob/master/src/main/java/at/rseiler/concept/Main.java!


package at.rseiler.concept;

import org.objectweb.asm.*;
import org.objectweb.asm.commons.AdviceAdapter;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.lang.reflect.Method;
import java.util.logging.Logger;

import static org.objectweb.asm.Opcodes.ASM4;
import static org.objectweb.asm.Opcodes.INVOKESTATIC;

/**
 * A demo how to do byte code transformation with ASM.
 * 
 * The program will load the HelloWorld class file and manipulate the byte code:
 * 
 * 1. Wraps static {@link Logger} into the {@link LoggerWrapper#logger(Logger)}
 * 2. Adds at the beginning of each method a call to {@link MethodLogger#log(String, Object...)}
 * 
 * 1.
 * private static final Logger logger1 = Logger.getLogger(HelloWorld.class.getName());
 * will be transformed into:
 * private static final Logger logger1 = LoggerWrapper.logger(Logger.getLogger(HelloWorld.class.getName()));
 * 
 * 2.
 * public String foo(String arg) {
 * return bar("foo", arg);
 * }
 * will be transformed into:
 * public String foo(String arg) {
 * MethodLogger.log("foo", arg);
 * return bar("foo", arg);
 * }
 * 
 * 
 * You shouldn't relay on the ASM version packed into the jdk for production code!
 * Because if a new Java version will be shipped than it could contain a new version of AMS (or remove ASM) which will break your code.
 * Therefor you must repackage ASM into your own namespace, to prevent version conflicts, and ship it with your library.
 * 
 * Because this is non production code and I am lazy I didn't do it.
 * 
 * IMPORTANT: If you try to run the program on a JMV other than the JDK8 it will probably fail.
 *
 * @author reinhard.seiler@gmail.com
 */
public class Main {

    public static void main(String[] args) throws Exception {
        // creates the ASM ClassReader which will read the class file
        ClassReader classReader = new ClassReader(new FileInputStream(new File("HelloWorld.class")));
        // creates the ASM ClassWriter which will create the transformed class
        ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_MAXS);
        // creates the ClassVisitor to do the byte code transformations
        ClassVisitor classVisitor = new MyClassVisitor(ASM4, classWriter);
        // reads the class file and apply the transformations which will be written into the ClassWriter
        classReader.accept(classVisitor, 0);

        // gets the bytes from the transformed class
        byte[] bytes = classWriter.toByteArray();
        // writes the transformed class to the file system - to analyse it (e.g. javap -verbose)
        new FileOutputStream(new File("HelloWorld$$Transformed.class")).write(bytes);

        // inject the transformed class into the current class loader
        ClassLoader classLoader = Main.class.getClassLoader();
        Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", String.class, byte[].class, int.class, int.class);
        defineClass.setAccessible(true);
        Class helloWorldClass = (Class) defineClass.invoke(classLoader, null, bytes, 0, bytes.length);

        // creates an instance of the transformed class
        Object helloWorld = helloWorldClass.newInstance();
        Method hello = helloWorldClass.getMethod("hello");
        // class the hello method
        hello.invoke(helloWorld);
    }

    private static class MyClassVisitor extends ClassVisitor {

        public MyClassVisitor(int i, ClassVisitor classVisitor) {
            super(i, classVisitor);
        }

        public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
            if (cv == null) {
                return null;
            }

            MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
            //  defines the static block in which the assignment of static variables happens.
            // E.g. private static final Logger logger = Logger.getLogger(HelloWorld.class.getName());
            // The assignment of the logger variable happens in .
            if ("".equals(name)) {
                return new StaticBlockMethodVisitor(mv);
            } else {
                // all other methods (static and none static)
                return new MethodLogger(mv, access, name, desc);
            }
        }

        class StaticBlockMethodVisitor extends MethodVisitor {
            StaticBlockMethodVisitor(MethodVisitor mv) {
                super(ASM4, mv);
            }

            @Override
            public void visitFieldInsn(int opcode, String owner, String name, String desc) {
                // checks for: putstatic // Field *:Ljava/util/logging/Logger;
                if ("Ljava/util/logging/Logger;".equals(desc)) {
                    // adds before the putstatic opcode the call to LoggerWrapper#logger(Logger) to wrap the logger instance
                    super.visitMethodInsn(INVOKESTATIC, "at/rseiler/concept/LoggerWrapper", "logger", "(Ljava/util/logging/Logger;)Ljava/util/logging/Logger;");
                }
                // do the default behaviour: add the putstatic opcode to the byte code
                super.visitFieldInsn(opcode, owner, name, desc);
            }
        }

        class MethodLogger extends AdviceAdapter {

            private final int access;
            private final String name;
            private final String desc;

            protected MethodLogger(MethodVisitor mv, int access, String name, String desc) {
                super(ASM4, mv, access, name, desc);
                this.access = access;
                this.name = name;
                this.desc = desc;
            }

            @Override
            protected void onMethodEnter() {
                // checks if the method is static.
                // The difference is that "this" is stored in ALOAD_0 and the arguments are stored in ALOAD_1, ALOAD_2, ...
                // But there is no "this" for a static method call. Therefor the arguments are stored in ALOAD_0, ALOAD_1 ,...
                // If we want to access the arguments we need to differentiate between static and non static method calls.
                boolean isStatic = (access & ACC_STATIC) > 0;

                int length = Type.getArgumentTypes(desc).length;

                // pushes the method name on the stack
                super.visitLdcInsn(name);
                // pushes the count of arguments on the stack
                // could be optimized if we would use iconst_0, iconst_1, ..., iconst_5 for 0 to 5.
                super.visitIntInsn(BIPUSH, length);
                // creates an object array with the count of arguments
                super.visitTypeInsn(ANEWARRAY, "java/lang/Object");

                // stores the arguments in the array
                for (int i = 0; i < length; i++) {
                    // duplicates the reference to the array. Because the AASTORE opcode consumes the stack element with the reference to the array.
                    super.visitInsn(DUP);
                    // could be optimized
                    super.visitIntInsn(BIPUSH, i);
                    // puts the value of the current argument on the stack
                    super.visitVarInsn(ALOAD, i + (isStatic ? 0 : 1));
                    // stores the value of the current argument in the array
                    super.visitInsn(AASTORE);
                }

                // calls the MethodLogger#log(String, Object...) method with the corresponding arguments - which we created just before
                super.visitMethodInsn(INVOKESTATIC, "at/rseiler/concept/MethodLogger", "log", "(Ljava/lang/String;[Ljava/lang/Object;)V");
            }
        }

    }

}