Total Pageviews

2019/03/14

[Spring Boot] java.lang.NoClassDefFoundError: org/aspectj/lang/annotation/Pointcut

Problem
When I add @EnableRetry annotation:
package com.example.test;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.retry.annotation.EnableRetry;

@EnableRetry
@SpringBootApplication
@ComponentScan(basePackages = "com.example")
public class TestApplication {

    public static void main(String[] args) {
        SpringApplication.run(TestApplication.class, args);
    }

}


Then startup my spring boot project, I got the following exception
Caused by: java.lang.NoClassDefFoundError: org/aspectj/lang/annotation/Pointcut
 at org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactory.<clinit>(AbstractAspectJAdvisorFactory.java:62) ~[spring-aop-5.1.2.RELEASE.jar:5.1.2.RELEASE]
 at org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator.initBeanFactory(AnnotationAwareAspectJAutoProxyCreator.java:82) ~[spring-aop-5.1.2.RELEASE.jar:5.1.2.RELEASE]
 at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.setBeanFactory(AbstractAdvisorAutoProxyCreator.java:63) ~[spring-aop-5.1.2.RELEASE.jar:5.1.2.RELEASE]
 at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeAwareMethods(AbstractAutowireCapableBeanFactory.java:1767) ~[spring-beans-5.1.2.RELEASE.jar:5.1.2.RELEASE]
 at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1732) ~[spring-beans-5.1.2.RELEASE.jar:5.1.2.RELEASE]
 at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:576) ~[spring-beans-5.1.2.RELEASE.jar:5.1.2.RELEASE]
 ... 15 common frames omitted
Caused by: java.lang.ClassNotFoundException: org.aspectj.lang.annotation.Pointcut
 at java.net.URLClassLoader.findClass(URLClassLoader.java:381) ~[na:1.8.0_151]
 at java.lang.ClassLoader.loadClass(ClassLoader.java:424) ~[na:1.8.0_151]
 at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:335) ~[na:1.8.0_151]
 at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ~[na:1.8.0_151]
 ... 21 common frames omitted


How-To
Lacking of spring-boot-starter-aop dependency in pom.xml is root cause. So you need to edit pom.xml as bellows:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example</groupId>
    <artifactId>test</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>test</name>
    <description>Demo project for Spring Boot</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.0.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.retry</groupId>
            <artifactId>spring-retry</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>


</project>



2019/03/13

[Spring boot] org.yaml.snakeyaml.scanner.ScannerException: mapping values are not allowed here

Problem
When I tried to startup my spring boot project, I got this exception:
Caused by: org.yaml.snakeyaml.scanner.ScannerException: mapping values are not allowed here
 in 'reader', line 16, column 17:
        diskdrive: C:
                    ^

 at org.yaml.snakeyaml.scanner.ScannerImpl.fetchValue(ScannerImpl.java:872)
 at org.yaml.snakeyaml.scanner.ScannerImpl.fetchMoreTokens(ScannerImpl.java:360)
 at org.yaml.snakeyaml.scanner.ScannerImpl.checkToken(ScannerImpl.java:226)
 at org.yaml.snakeyaml.parser.ParserImpl$ParseBlockMappingKey.produce(ParserImpl.java:557)
 at org.yaml.snakeyaml.parser.ParserImpl.peekEvent(ParserImpl.java:157)
 at org.yaml.snakeyaml.parser.ParserImpl.checkEvent(ParserImpl.java:147)
 at org.yaml.snakeyaml.composer.Composer.composeMappingNode(Composer.java:227)
 at org.yaml.snakeyaml.composer.Composer.composeNode(Composer.java:154)
 at org.yaml.snakeyaml.composer.Composer.composeValueNode(Composer.java:249)
 at org.yaml.snakeyaml.composer.Composer.composeMappingChildren(Composer.java:240)
 at org.yaml.snakeyaml.composer.Composer.composeMappingNode(Composer.java:228)
 at org.yaml.snakeyaml.composer.Composer.composeNode(Composer.java:154)
 at org.yaml.snakeyaml.composer.Composer.composeValueNode(Composer.java:249)
 at org.yaml.snakeyaml.composer.Composer.composeMappingChildren(Composer.java:240)
 at org.yaml.snakeyaml.composer.Composer.composeMappingNode(Composer.java:228)
 at org.yaml.snakeyaml.composer.Composer.composeNode(Composer.java:154)
 at org.yaml.snakeyaml.composer.Composer.composeDocument(Composer.java:122)
 at org.yaml.snakeyaml.composer.Composer.getNode(Composer.java:84)
 at org.yaml.snakeyaml.constructor.BaseConstructor.getData(BaseConstructor.java:123)
 at org.yaml.snakeyaml.Yaml$1.next(Yaml.java:547)

Here had part of application.yml
opendata:
  file:
    diskdrive: C:
    subdirectory: opendata



How-To
I should add double quote to C: in head and tail. application.yml should modify as bellows:
opendata:
  file:
    diskdrive: "C:"
    subdirectory: opendata




2019/03/12

[SQL Server] IF EXISTS update else insert

Scenario
If I would like to implement a SQL statement to fulfill the following requirement, how to do it?


How-To
You can utilize if exists..else to do, here has an example:
  IF EXISTS (select * from TEST where ID = :id)
    UPDATE TEST 
    SET USER_ID = :userId, 
 USER_NAME = :userName, 
 LAST_UPDATE_TIME = getdate() 
    WHERE ID = :id
  ELSE
    INSERT INTO TEST (ID, 
                      USER_ID, 
            USER_NAME, 
        CREATE_TIME, 
        LAST_UPDATE_TIME)
               VALUES (:id, 
         :userId, 
         :userName, 
         getdate(), 
         getdate())
  ;


2019/03/11

[Java] [Design Pattern] An example for Template Method Pattern

Here has four steps to demonstrate template method pattern:

1. Create an abstract class with a template method being final.
package com.example.pattern.template;

public abstract class Game {

    abstract void initializeGame();
    abstract void playGame();
    abstract void endGame();

    /**
     * template method
     */
    public final void play() {
        initializeGame();
        playGame();
        endGame();
    }

}

2. Create concrete classes extending the above class.
package com.example.pattern.template;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class FishingStrike extends Game {

    @Override
    void initializeGame() {
        log.debug("Fishing Strike initialized!");
    }

    @Override
    void playGame() {
        log.debug("Fishing Strike started! Enjoy the game!");
    }

    @Override
    void endGame() {
        log.debug("Fishing Strike finished! See you!");
    }
}


package com.example.pattern.template;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class MiniGolfKing extends Game {

    @Override
    void initializeGame() {
        log.debug("Mini Golf King initialized!");
    }

    @Override
    void playGame() {
        log.debug("Mini Golf King started! Enjoy the game!");
    }

    @Override
    void endGame() {
        log.debug("Mini Golf King finished! See you!");
    }
}


3. Create a demo class to use the Game's template method play() to demonstrate a defined way of playing game.
package com.example.pattern.template;

import org.springframework.stereotype.Component;

@Component
public class TemplatePatternDemo {

    /**
     * play fishing strike game
     */
    public void playFishingStrike() {
        Game fishingStrike = new FishingStrike();
        fishingStrike.play();
    }

    /**
     * play mini golf king game
     */
    public void playMiniGolfKing() {
        Game miniGolfKing = new MiniGolfKing();
        miniGolfKing.play();
    }

}


4. Autowired TemplatePatternDemo to play execute methods and verify output
package com.example.test;

import com.example.pattern.template.TemplatePatternDemo;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;

@SpringBootApplication
@ComponentScan(basePackages = "com.example")
public class TestApplication {

    public static void main(String[] args) {
        SpringApplication.run(TestApplication.class, args);
    }

    @Bean
    CommandLineRunner run(TemplatePatternDemo demo) {
        return args -> {
            demo.playFishingStrike();
            demo.playMiniGolfKing();
        };
    }
}


[main] c.e.pattern.template.FishingStrike       : Fishing Strike initialized!
[main] c.e.pattern.template.FishingStrike       : Fishing Strike started! Enjoy the game!
[main] c.e.pattern.template.FishingStrike       : Fishing Strike finished! See you!
[main] c.example.pattern.template.MiniGolfKing  : Mini Golf King initialized!
[main] c.example.pattern.template.MiniGolfKing  : Mini Golf King started! Enjoy the game!
[main] c.example.pattern.template.MiniGolfKing  : Mini Golf King finished! See you!




2019/03/10

[Database] [Sybase] arithmetic overflow error

Problem
When I try to sum up a integer column in Sybase, I get arithmetic overflow error, how to fix it?
SELECT SUM(columnname) 
FROM tablename

How-To
Simply cast this column to big integer can solve this problem, the updated query SQL statement is as bellows;
SELECT SUM( cast(columnname as BIGINT)) 
FROM tablename

2019/03/09

[Angular 6] Can't bind to 'ngModel' since it isn't a known property of 'input'

Problem
When I try to run my html page, it showed the following error message:
When I try to run my html page, it showed the following error message:
compiler.js:1021 Uncaught Error: Template parse errors:
Can't bind to 'ngModel' since it isn't a known property of 'input'. ("up)="changeKeyword($event.target.value)"
                (keyup.esc)="clearKeyword($event.target)" [ERROR ->][(ngModel)]="keyword">
              <input type="button" value="搜尋" id="searchbutton">


How-To
I forgot to import FormsModule in my app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';

import { AppComponent } from './app.component';
import { Page2Component } from './page2/page2.component';

@NgModule({
  declarations: [
    AppComponent,
    Page2Component
  ],
  imports: [
    BrowserModule,
    FormsModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }
     


2019/03/08

[Spring Boot] How to configure multiple datasource in Spring boot?

Problem
I have Sybase and Microsoft SQL Server database connection in my Spring boot, how to configure two data source in my project?

Sybase repository and entity classes are located in test.repository.sybase, and test.entity.sybase

Microsoft SQL Server repository and entity classes are located in test.repository.sqlserver and test.entity.sqlserver


How-To
Configure 2 database configuration in application.yml:
spring:
  jpa:
    show-sql: true
    open-in-view: false
    hibernate:
      naming:
        physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
  datasource:
    url: jdbc:sybase:Tds:192.168.0.1:5000/TEST
    username: user
    password: secret
    driver-class-name: com.sybase.jdbc4.jdbc.SybDriver
    hikari:
      pool-name: pool-primary
      connection-test-query: SELECT 1

sqlserver:      
    datasource:
      url: jdbc:sqlserver://192.168.0.2:1433
      username: user
      password: secret
      driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver
      hikari:
        pool-name: pool-sqlserver
        connection-test-query: SELECT 1

Sybase configuration:
package test.config;

import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.autoconfigure.jdbc.JdbcProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;

import com.zaxxer.hikari.HikariDataSource;

@Configuration
@Primary
@EnableJpaRepositories(transactionManagerRef = "transactionManager", basePackages = {
        "test.repository.sybase" })
public class SybaseDbConfig {

    @Value("${spring.datasource.url}")
    private String url;

    @Value("${spring.datasource.username}")
    private String username;

    @Value("${spring.datasource.password}")
    private String password;

    @Value("${spring.datasource.driver-class-name}")
    private String driver;

    @Bean
    @Primary
    @ConfigurationProperties(prefix = "spring.datasource.hikari")
    public HikariDataSource dataSource(DataSourceProperties dataSourceProperties) {
        return dataSourceProperties.initializeDataSourceBuilder().type(HikariDataSource.class)
                .build();
    }

    @Bean
    @Primary
    public JdbcTemplate jdbcTemplate(@Qualifier("dataSource") DataSource dataSource,
            JdbcProperties properties) {
        return new JdbcTemplate(dataSource);
    }

    @Bean
    @Primary
    public NamedParameterJdbcTemplate namedParameterJdbcTemplate(
            @Qualifier("jdbcTemplate") JdbcTemplate jdbcTemplate) {
        return new NamedParameterJdbcTemplate(jdbcTemplate);
    }

    @Bean(name = "entityManagerFactory")
    public LocalContainerEntityManagerFactoryBean entityManagerFactory(
            EntityManagerFactoryBuilder builder, @Qualifier("dataSource") DataSource dataSource) {
        return builder.dataSource(dataSource).packages("test.entity.sybase")
                .persistenceUnit("sybase").build();
    }

    @Bean(name = "transactionManager")
    public PlatformTransactionManager transactionManager(
            @Qualifier("entityManagerFactory") EntityManagerFactory entityManagerFactory) {
        return new JpaTransactionManager(entityManagerFactory);
    }

}


Microsoft SQL Server Configuration:
package test.config;

import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;

import com.zaxxer.hikari.HikariDataSource;

@Configuration
@EnableJpaRepositories(entityManagerFactoryRef = "sqlserverEntityManagerFactory", 
                       transactionManagerRef = "sqlserverTransactionManager", 
                       basePackages = {"test.repository.sqlserver" })
public class SqlServerDbConfig {

    @Value("${sqlserver.datasource.url}")
    private String url;

    @Value("${sqlserver.datasource.username}")
    private String username;

    @Value("${sqlserver.datasource.password}")
    private String sqlPassword;

    @Value("${sqlserver.datasource.driver-class-name}")
    private String sqlDriver;

    @Bean
    @Qualifier("sqlserverDataSource")
    @ConfigurationProperties(prefix = "npa.ai.datasource.hikari")
    public HikariDataSource sqlserverDataSource() {
        return DataSourceBuilder.create().url(url).username(username).password(sqlPassword)
                .driverClassName(sqlDriver).type(HikariDataSource.class).build();
    }

    @Bean
    @Qualifier("sqlserverJdbcTemplate")
    public JdbcTemplate sqlserverJdbcTemplate(@Qualifier("sqlserverDataSource") DataSource sqlserverDataSource) {
        return new JdbcTemplate(sqlserverDataSource);
    }

    @Bean
    @Primary
    public NamedParameterJdbcTemplate namedParameterJdbcTemplate(
            @Qualifier("sqlserverJdbcTemplate") JdbcTemplate jdbcTemplate) {
        return new NamedParameterJdbcTemplate(jdbcTemplate);
    }

    @Bean(name = "sqlserverEntityManagerFactory")
    public LocalContainerEntityManagerFactoryBean sqlserverEntityManagerFactory(
            EntityManagerFactoryBuilder builder,
            @Qualifier("sqlserverDataSource") DataSource sqlserverDataSource) {
        return builder.dataSource(sqlserverDataSource).packages("test.entity.sqlserver")
                .persistenceUnit("sqlserver").build();
    }

    @Bean(name = "sqlserverTransactionManager")
    public PlatformTransactionManager sqlserverTransactionManager(
            @Qualifier("sqlserverEntityManagerFactory") EntityManagerFactory sqlserverEntityManagerFactory) {
        return new JpaTransactionManager(sqlserverEntityManagerFactory);
    }

}



Reference
[1] https://scattercode.co.uk/2016/01/05/multiple-databases-with-spring-boot-and-spring-data-jpa/

2019/03/07

[Chrome] JSON Formatter Plugin

Problem
I am using Spring Actuator to monitor our app, gathering metrics, understanding traffic or the state of our database becomes trivial with this dependency.The main benefit of this library is that we can get production grade tools without having to actually implement these features ourselves. 

Actuator is mainly used to expose operational information about the running application – health, metrics, info, dump, env, etc. 

And it will provide information for me with JSON format:

But the JSON is not formatted, how to format the output JSON?


How-To
Install Chrome plugin to fulfill this requirement: https://chrome.google.com/webstore/detail/json-formatter/bcjindcccaagfpapjjmafapmmgkkhgoa/


2019/03/06

[Eclipse] Get the power to write better code with sonarlint

You can install sonarlint plugin to get the power to write better code.
For example, if you forgot to close IO resource properly, you will get this hint:

And it will tell you how to fix this problem: