Archives

now browsing by author

 

Developing java apps on VS Code

VSCode

An integrated development environment (IDE) is a software suite that consolidates basic tools required to write and test software..
For a long time there have been basically 3 big players in the java IDE world: Netbeans, Eclipse and IntelliJ IDEA. According to some surveys IntelliJ IDEA is clearly winning the IDE battle, Eclipse is loosing popularity year over year, and Netbeans is basically hanging.
I personally I am part of the “minority” that uses Netbeans for my java development. There were simple things I liked about Netbeans over its competitors, and even though I tried to use Eclipse or IntelliJ, and I saw they are potentially way better than Netbeans, I was always coming back to my familiar Netbeans no matter what. Why was that? Here is the simple things I am looking for in an IDE:
- syntax highlighting for at least: Java, JavaScript, Html, CSS
- build/test/run project from IDE
- ability to see javadocs directly from IDE
- easy jump from one class to another
- code refactoring assistance
- intelligent code completion

Lots of features are great, but b/c I am using only a handful of those provided features, I rather not have to always dig into overpopulated drop down menus. Remembering shortcut keys will always solve this problem.

Most (all) of my projects are maven/gradle based; I like being able to just open my project directly, not having to import it in some kind of proprietary project format, setup workspaces and install external plugins before I get to work.

Over time I started finding Netbeans getting in the way of my productivity. There were numerous annoyances, small problems popping up all the time. The cause of these problems might by me, my project setup, the frameworks I use, my OS, my all around environment, Netbeans itself or a combination of all the above. The plan was to succomb to pressure and get a IntelliJ license. Everybody uses it, and I am being told it does everything but cooking your breakfast. Al I have to do is adjust my workflow to a new environment, and maybe lear some new shortcuts.

I am a big fan of opensource projects, and not a big fan of subscriptions, licenses and dealing with support. Those were some of the reasons why I did not buy the license after all. Plus I had the community version installed on my machine, but I was still using Netbeans for some reason.

I need to ditch Netbeans, but today as I am writing this, I know that my next IDE will not be IntelliJ (nor Eclipse). And this is b/c I tried Visual Studio Code/.

As their github page says https://github.com/Microsoft/vscode. VS Code is a type of tool that combines the simplicity of a code editor with what developers need for their core edit-build-debug cycle. I has powerful developer tooling, like IntelliSense code completion and debugging and gets out of your way.

Sounded good. But … First thing first. You might have noticed that this is a software coming from Microsoft, a company that historically has not been too friendly to the open source world, but they have changed their position/opinion in the last years. (Or have they???).

This product is open source and free for private or commercial use (MIT license). Nice.
Another big plus is the fact that VS Code is multi-platform. All my computers run Linux, so this is an important aspect.

First time you open VS Code, it does feel like you opened a simple editor. Similar layout, color palette, even the nice scrollbar with content preview (minimap) and highligting like the sublime text editor. The only additional thing is an activity bar with a few square icons:
- Explorer
- Search
- Source Control
- Debug
- Extensions

That’s it. Clicking on any of those icons brings in front different panels, often minimalist that are self explanatory, a user that has been previously exposed to a full fledged IDE can just explore and feel rigt at home in no time. I am using git, and the source control section allows me out of the box to see staged/unstaged changes in the current branch + allow to see a graphical diff between my current file and the one on HEAD. Of course there is support for other git operations directly from the UI, that I will probably not use b/c I like to do all my git operations directly in the terminal.

The editor that VS Code uses is a deparate project, have a look at the the Monaco Editor. Looks like it’s implemented in typeScript (typed JavaScript) and it is an editor that can run in a browser. Digging a little into it, I found out that they use Electron a tool which uses blink browser engine (used in chromium) and node.js to allow building cross platform desktop apps with JavaScript, HTML, and CSS (web technologies).

Looks like basic web front end development is supported from the get go, but java development, is supported via additional extensions.
Installing extensions is pretty easy. You just click the extension quick icon on the left bar and search through the market place. I searched for java, and I went with installing the following:
- Red Hat: Language Support for Java(TM) by Red Hat – Java Linting, IntelliSense, formatting, refactoring, Maven/Gradle support and more…
- Microsoft: Debugger for Java – a lightweight Java debugger for Visual Studio Code
- Microsoft: Java Test Runner – Run and debug JUnit or TestNG test cases
- Wei Shen: Tomcat for Java – Debug or run your java war package in Apache Tomcat

!!! Careful with the extensions. It might cause your IDE to become unstable. That’s the reason I tried to stay with the lowest number of installed extensions.
Also I wanted big reputable companies behind the chosen extensions. (The outliner is the Tomcat extension which is community supported).

The java Language Server here is where all the java magic is coming from. Features like auto complete, diagnostics, go to definition, find all references and alike can be found in one of the projects used. Eclipse JDT brings in important features like Java debug support, and annotation processing infrastructure.

I am not going to enumerate the few problems I run into, b/c judging by the release schedule and the amount of contributors, activity and attention this project gets, my issues will be solved in no time. Also the main things I rely on are coming from the Eclipse foundation, they are stable and proved projects. All I can say is that after I installed the java extension, there was absolutely no feature I was missing in an IDE. Here is what I tried/needed.
- open/setup maven project
- clean/build/test maven project
- run/debug independent Junit test
- format file
- run/debug war file on Tomcat
- auto reload jsp code on Tomcat
- InteliSense with all features: code completion, see java doc, jump to, etc
- built in bash terminal
- jump to current file in tree panel
- diff file(s) to HEAD or to other branches
- quickly search and jump to files in project
- highlighting of syntax error in the editor
- code refactoring assistance
- auto import
- generate code (java bean getters/setters)
- problems panel: where I can see my annotated TODO/FIXME + other potential problems

Conclusion. Although this IDE is relative new (about 3 years old), I feel like for me it’s the most suitable IDE I have ever tried. It seemed like it was designed for ease of use, with a minimalist default setup. It has about the right amount of features and it has the 21st century look and feel. It is not there yet, but I will be coming back on each one of the new releases, until I will fully adopt it as my main IDE.

JPA set null on delete

Java

I am sure a lot of you heard, when talking about RDBMS systems about a foreign key with “Set NULL on delete”. It means that if a record in the parent table is deleted, then the corresponding records in the child table will have the foreign key fields set to NULL. The records in the child table will not be deleted. A foreign key with set null on delete can be created at the beginning when a table gets created (CREATE TABLE statement) or later on (ALTER TABLE statement).

I needed the same type of behavior, but done in my DAO layer where I happened to use Java Persistence API.

Following is the solution. We will be working with 2 entities, here is are some simple implementations of a Child class and a Parent class.

@Entity
@Table(name = "c_child")
public class Child {
    @Id
    @GeneratedValue(strategy = IDENTITY)
    @Column(name = "id", unique = true, nullable = false)
    private Integer id;

    @ManyToOne
    @JoinColumn(name = "parent_id")
    private Parent parent;

    public Integer getId() {
        return this.id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public Parent getParent() {
        return parent;
    }

    public void setParent(Parent parent) {
        this.parent = parent;
    }
}
@Entity
@Table(name = "c_parent")
public class Parent {
    @Id
    @GeneratedValue(strategy = IDENTITY)
    @Column(name = "id", unique = true, nullable = false)
    private Integer id;

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "parent")
    private Set<Child> children;

    public Integer getId() {
        return this.id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public Set<Child> getChildren() {
        return children;
    }

    public void setChildren(Set<Child> children) {
        this.children = children;
    }

    @PreRemove
    private void removeParentFromChildren() {
        for (Child child : this.getChildren()) {
            child.setParent(null);
        }
    }
}

With this setup in place whenever the parent will be removed from the storage ( entitymanager.remove(parent) ), after.if the transaction is commited, all the children that had the deleted parent will now have null. So, as you can see the solution is a simple callback method annotated with the JPA provided @PreRemove. A callback method is a no-arg method with no return type and any arbitrary name. The callback I used is only one of the many that JPA API provides

Type Description
@PrePersist Executed before the entity manager persist operation is
actually executed or cascaded. This call is synchronous with the
persist operation.
@PreRemove Executed before the entity manager remove operation is
actually executed or cascaded. This call is synchronous with the
remove operation.
@PostPersist Executed after the entity manager persist operation is
actually executed or cascaded. This call is invoked after the
database INSERT is executed.
@PostRemove Executed after the entity manager remove operation is
actually executed or cascaded. This call is synchronous with the
remove operation.
@PreUpdate Executed before the database UPDATE operation.
@PostUpdate Executed after the database UPDATE operation.
@PostLoad Executed after an entity has been loaded into the current
persistence context or an entity has been refreshed.

JPA Injection in AttributeConverters

Java

Here is the use case. We have a table in the database that has a column where we keep a sensitive piece of information.
That is why this column was made of type VARBINARY and the data kept in it is encrypted. (using the AES algorithm)

 CREATE TABLE `example` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `username` varchar(25) NOT NULL,
  `password` varbinary(200) NOT NULL
  PRIMARY KEY (`id`),
) ENGINE=InnoDB;

We wanted to be able to load the decrypted password directly into the JPA @Entity that is modeled according to that table.

@Entity
@Table(name = "example")
public class Example {

    @Id
    @GeneratedValue(strategy = IDENTITY)
    @Column(name = "id")
    private Integer id;

    @Column(name = "username", nullable = false, length = 25)
    private String username;

    @Column(name = "password", nullable = false)
    @Convert(converter = AesConverter.class)
    private char[] password;

    public Integer getId() {
        return this.id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUsername() {
        return this.username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public char[] getPassword() {
        return password != null ? password.clone() : null;
    }

    public void setPassword(char[] password) {
        this.password = password != null ? password.clone() : null;
    }
}    

As you can see we have a AesConverter class that is taking care of this. This is just an implementation of AttributeConverter that does the encryption/decryption, by delegating to another utility class AesUtil.

@Converter
public class AesConverter implements AttributeConverter<char[], byte[]> {

    @Resource(name = "dbEncryptionKey")
    private String dbEncryptionKey;

    @Override
    public byte[] convertToDatabaseColumn(char[] chars) {
        return AesUtil.encryptMySqlAes(chars, this.dbEncryptionKey);
    }

    @Override
    public char[] convertToEntityAttribute(byte[] bytes) {
        return AesUtil.decryptMySqlAes(bytes, this.dbEncryptionKey);
    }

}

In our example we use CDI and we configured the app in such a way that that the AesConverter.java file is picked up by the CDI container.
We are using Hibernate 5.3.x which implements JPA 2.2, so the bean named “dbEncryptionKey” which exists in the CDI context from a properties file just gets injected in our converter, so we are ready to go everything works like a charm.

Now, what to do, when using Hibernate 5.2.x or lower, or another JPA implementation that supports JPA 2.1 (did not upgrade to JPA 2.2)
Here is our solution.

@Converter
public class AesConverter implements AttributeConverter<char[], byte[]> {

    @Override
    public byte[] convertToDatabaseColumn(char[] chars) {
        return AES.getInstance().encrypt(chars);
    }

    @Override
    public char[] convertToEntityAttribute(byte[] bytes) {
        return AES.getInstance().decrypt(bytes);
    }

}

where AES.java is a singleton that uses a service locator to lazily load the needed encryption key from the CDI context only when first needed.

public class AES {

    private static final String DEFAULT_ENCRYPTION_KEY = "s3Cr!t";
    private String dbEncryptionKey = DEFAULT_ENCRYPTION_KEY;

    private static AES instance;

    private AES() {
        if (DEFAULT_ENCRYPTION_KEY.equals(this.dbEncryptionKey)) {
            this.getConfiguredEncryptionKey();
        }
    }    
    
    private AES(String dbEncryptionKey) {
        this.dbEncryptionKey = dbEncryptionKey;
    }

    public static AES getInstance(String dbEncryptionKey) {
        synchronized (AES.class) {
            if (instance == null) {
                instance = new AES(dbEncryptionKey);
            }
        }
        return instance;
    }

    public static AES getInstance() {
        synchronized (AES.class) {
            if (instance == null) {
                instance = new AES();
            }
        }
        return instance;
    }

    public char[] decrypt(byte[] bytes) {
        return AesUtil.decryptMySqlAesPassword(bytes, this.dbEncryptionKey);
    }

    public byte[] encrypt(char[] input) {
        return AesUtil.encryptMySqlAesPassword(input, this.dbEncryptionKey);
    }

    private void getConfiguredEncryptionKey() {
        try {
            this.mhqDbEncryptionKey = ContextLocator.getRegisteredBean("dbEncryptionKey");
        } catch (IllegalStateException isx) {
            isx.printStackTrace();
        }
    }
}

App performance logging using Advice

Java

Use case. We have a java webapp in PROD using the usual MySQL/Hibernate/Spring.
We were trying to find out where (what methods) are the ones where the most execution time is being spent.
Here is our solution, using AOP.

// source file LogHandler.java
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LogHandler {
    LogType[] logTypes() default {LogType.APPLICATION};
}

// source file LogType.java
public enum LogType {
    PERFORMANCE, APPLICATION;
}


// source file LoggingProxy.java
@Component
@Aspect
public class LoggingProxy {

    private static final Logger LOGGER = LoggerFactory.getLogger(LoggingProxy.class);
    private static final Logger PERFORMANCE_LOGGER = LoggerFactory.getLogger("com.neemeekaa.performance");

    @Around("(@annotation(logHandler))")
    public Object around(final ProceedingJoinPoint pjp, final LogHandler logHandler) throws Throwable {
        final String methodName = pjp.getSignature().getName();
        LOGGER.debug("Start to process call[{}], identify by LogHandler annotation", methodName);
        final List<LogType> logTypes = Arrays.asList(logHandler.logTypes());
        final StopWatch stopWatch = new StopWatch();
        try {
            stopWatch.start();
            final Object proceed = pjp.proceed();
            if (logTypes.contains(LogType.APPLICATION)) {
                LOGGER.debug("Method [{}] returned: {}", methodName, proceed);
            }
            printOperation(logTypes, stopWatch, methodName);
            return proceed;
        } catch (final Throwable exception) {
            printOperation(logTypes, stopWatch, methodName, exception);
            LOGGER.error("Error at method {}", methodName, exception);
            throw new RuntimeException(exception);
        }
    }

    private void printOperation(final List<LogType> logTypes, final StopWatch stopWatch, final String methodName) {
        if (logTypes.contains(LogType.PERFORMANCE)) {
            stopWatch.stop();
            PERFORMANCE_LOGGER.info("Time elapsed for method {} is: {} ms", methodName, stopWatch.getTotalTimeMillis());
        }
        LOGGER.info("Method '{}' returned with success", methodName);
    }

    private void printOperation(final List<LogType> logTypes, final StopWatch stopWatch, final String methodName, final Throwable throwable) {
        if (logTypes.contains(LogType.PERFORMANCE)) {
            stopWatch.stop();
            PERFORMANCE_LOGGER.info("Time elapsed for method {} is: {} ms", methodName, stopWatch.getTotalTimeMillis());
        }

        final String message = String.format("%s returned a %s exception", methodName, throwable.getMessage());
        LOGGER.info(message);
    }

}

We are using logback.xml as logging framework. Here is a simplified config file we use:

<!-- logback.xml-->
<configuration>

    <statusListener class="ch.qos.logback.core.status.OnConsoleStatusListener"/>

    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>%d{YYYY-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>

    <appender name="PERFORMANCE_APPENDER" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${HOME}/app-performance.log</file>
        <encoder>
            <pattern>%d{YYYY-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${HOME}/app-security.%d{yyyy-MM-dd}.log.zip</fileNamePattern>
        </rollingPolicy>
    </appender>

    <logger name="com.neemeekaa" level="DEBUG"/>

    <logger name="com.neemeekaa.performance" level="DEBUG">
        <appender-ref ref="PERFORMANCE_APPENDER"/>
    </logger>

    <root level="INFO">
        <appender-ref ref="STDOUT"/>
        <appender-ref ref="PERFORMANCE_APPENDER"/>
    </root>

</configuration>

Now all we have to do is annotate the method we want with:

@LogHandler(logTypes = {LogType.PERFORMANCE})

and all the information we need is routed into the app-performance.log

JPA calculated field

Java

Here is my usecase. I have a JPA entity, Unit containing address fields. Country and State are separate entities (in different SQL tables), that are being tied to my Unit using a @ManyToOne association. I was trying to compute a fullAddress String, using all the address fields available using a method like the following:

    public String getFullAddress() {

        String result = this.address1;
        result = (this.address2 != null) ? result + " " + this.address2 + "," : result + ",";
        result = result + " " + this.city;

        if (this.state != null) {
            result = " " + this.state.getCode() + ",";
        }
        if (this.country != null) {
            result = result + " " + this.country.getShortName();
        }
        if (this.postalCode != null) {
            result = result + " " + this.postalCode;
        }
        return result;
    }

The problem was that at the time I was calling the getFullAddress() method my Hibernate session no longer exists, so the call was failing with a org.hibernate.LazyInitializationException: could not initialize proxy – no Session. Instead of eagerly fetching the state and country entities I decided to go on a different route.

@Entity
@EntityListeners({ UnitListener.class })
@Table(name = "unit", uniqueConstraints = { @UniqueConstraint(columnNames = "unit_number")})
public class Unit {

    @Id
    @GeneratedValue(strategy = IDENTITY)
    @Column(name = "id", unique = true, nullable = false)
    private Integer id;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "state_id")
    private HState state;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "country_id")
    private HCountry country;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "manager_id")
    private OrgManager orgManager;

    @Column(name = "unit_name", nullable = false, length = 100)
    private String unitName;

    @Column(name = "unit_number", unique = true, nullable = false, length = 12)
    private String unitNumber;

    @Column(name = "address_1")
    private String address1;

    @Column(name = "address_2")
    private String address2;

    @Column(name = "city", length = 100)
    private String city;

    @Column(name = "postal_code", length = 32)
    private String postalCode;

    @Transient
    private String fullAddress;

    // getter + setter omitted for brevity 

}

As you can see I added a new transient field in the Unit bean, the @Transient annotation tells JPA that the field is not persistent. In order to have this populated with the String I really wanted I had to create a new entity listener which I called UnitListener. The implementation of this listener is pretty simple, it is the same code, in a method annotated with @PostLoad

public class UnitListener {

    @PostLoad
    private void unitPostLoad(CUnit unit) {
        String fullAddress = unit.getAddress1();
        fullAddress = (unit.getAddress2() != null) ? fullAddress + " " + unit.getAddress2() + "," : fullAddress + ",";
        fullAddress = fullAddress + " " + unit.getCity();

        if (unit.getState() != null) {
             fullAddress = fullAddress + " " + unit.getState().getCode() + ",";
        }
        if (unit.getCountry() != null) {
             fullAddress = fullAddress + " " + unit.getCountry().getShortName(;
        }
        if (unit.getPostalCode() != null) {
             fullAddress = fullAddress + " " + unit.getPostalCode();
        }

        unit.setFullAddress(fullAddress);

    }
}

@PostLoad is just one of the annotations in the JPA specifications that designate lifecycle event callback methods of the corresponding types.
Other annotations are available:
• PrePersist
• PrePersist
• PostPersist
• PreRemove
• PostRemove
• PreUpdate
• PostUpdate

For more info, the JPA specs are available to download from Oracle website.