Programming Posts

Create a Simple CRUD REST API using Quarkus

Just several days ago, Quarkus release version 2.0, providing more features and some more improvements in this release. In this tutorial, we’ll try to see how can we use the latest Quarkus version to create a simple rest api, which is connect to an existing MySQL database by using hibernate.

Lets start with a simple pom.xml file,

<?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.edw</groupId>
    <artifactId>hello-world-quarkus</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <compiler-plugin.version>3.8.1</compiler-plugin.version>
        <maven.compiler.parameters>true</maven.compiler.parameters>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <quarkus.platform.artifact-id>quarkus-universe-bom</quarkus.platform.artifact-id>
        <quarkus.platform.group-id>io.quarkus</quarkus.platform.group-id>
        <quarkus.platform.version>2.0.0.Final</quarkus.platform.version>
        <surefire-plugin.version>3.0.0-M5</surefire-plugin.version>
    </properties>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>${quarkus.platform.group-id}</groupId>
                <artifactId>${quarkus.platform.artifact-id}</artifactId>
                <version>${quarkus.platform.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-hibernate-orm</artifactId>
        </dependency>
        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-resteasy</artifactId>
        </dependency>
        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-resteasy-jsonb</artifactId>
        </dependency>
        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-jdbc-mysql</artifactId>
        </dependency>
        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-arc</artifactId>
        </dependency>
        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-junit5</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>io.rest-assured</groupId>
            <artifactId>rest-assured</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>${quarkus.platform.group-id}</groupId>
                <artifactId>quarkus-maven-plugin</artifactId>
                <version>${quarkus.platform.version}</version>
                <extensions>true</extensions>
                <executions>
                    <execution>
                        <goals>
                            <goal>build</goal>
                            <goal>generate-code</goal>
                            <goal>generate-code-tests</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>${compiler-plugin.version}</version>
                <configuration>
                    <parameters>${maven.compiler.parameters}</parameters>
                </configuration>
            </plugin>
            <plugin>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>${surefire-plugin.version}</version>
                <configuration>
                    <systemPropertyVariables>
                        <java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
                        <maven.home>${maven.home}</maven.home>
                    </systemPropertyVariables>
                </configuration>
            </plugin>
        </plugins>
    </build>
    <profiles>
        <profile>
            <id>native</id>
            <activation>
                <property>
                    <name>native</name>
                </property>
            </activation>
            <build>
                <plugins>
                    <plugin>
                        <artifactId>maven-failsafe-plugin</artifactId>
                        <version>${surefire-plugin.version}</version>
                        <executions>
                            <execution>
                                <goals>
                                    <goal>integration-test</goal>
                                    <goal>verify</goal>
                                </goals>
                                <configuration>
                                    <systemPropertyVariables>
                                        <native.image.path>
                                            ${project.build.directory}/${project.build.finalName}-runner
                                        </native.image.path>
                                        <java.util.logging.manager>org.jboss.logmanager.LogManager
                                        </java.util.logging.manager>
                                        <maven.home>${maven.home}</maven.home>
                                    </systemPropertyVariables>
                                </configuration>
                            </execution>
                        </executions>
                    </plugin>
                </plugins>
            </build>
            <properties>
                <quarkus.package.type>native</quarkus.package.type>
            </properties>
        </profile>
    </profiles>
</project>

Next is creating a simple java model, as table representation

package com.edw.model;

import javax.persistence.*;
import java.math.BigDecimal;
import java.util.Date;

@Entity
@Table(name = "T_TRANSFER")
public class Transfer {
    @Id
    @GeneratedValue(strategy= GenerationType.AUTO)
    private Long id;
    private String accountFrom;
    private String accountTo;
    private Date transferDate;
    private BigDecimal amount;

    public Transfer() {
    }

    public Long getId() {
        return id;
    }

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

    public String getAccountFrom() {
        return accountFrom;
    }

    public void setAccountFrom(String accountFrom) {
        this.accountFrom = accountFrom;
    }

    public String getAccountTo() {
        return accountTo;
    }

    public void setAccountTo(String accountTo) {
        this.accountTo = accountTo;
    }

    public Date getTransferDate() {
        return transferDate;
    }

    public void setTransferDate(Date transferDate) {
        this.transferDate = transferDate;
    }

    public BigDecimal getAmount() {
        return amount;
    }

    public void setAmount(BigDecimal amount) {
        this.amount = amount;
    }
}

After that we can create a simple class for querying using EntityManager,

package com.edw.service;

import com.edw.dto.TransferDto;
import com.edw.model.Transfer;

import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.transaction.Transactional;
import java.util.Date;
import java.util.HashMap;
import java.util.List;

@Transactional
@ApplicationScoped
public class TransferService {
    @Inject
    EntityManager em;

    public List<Transfer> findAll() {
        return em.createQuery("select t from Transfer t", Transfer.class).getResultList();
    }

    public Long create(TransferDto transferDto) {
        Transfer transfer = new Transfer();
        transfer.setAccountFrom(transferDto.getAccountFrom());
        transfer.setAccountTo(transferDto.getAccountTo());
        transfer.setAmount(transferDto.getAmount());
        transfer.setTransferDate(new Date());
        em.persist(transfer);

        return transfer.getId();
    }

}

And a controller to handle rest api request,

package com.edw.controller;

import com.edw.dto.TransferDto;
import com.edw.service.TransferService;

import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.util.HashMap;

@Path("/transfer")
public class TransferController {

    @Inject
    TransferService transferService;

    @GET
    @Path("/")
    @Produces(MediaType.APPLICATION_JSON)
    public Response findAll() {
        return Response
                .ok(transferService.findAll())
                .build();
    }

    @POST
    @Path("/")
    @Produces(MediaType.APPLICATION_JSON)
    public Response create(TransferDto transferDto) {
        try {
            Long id = transferService.create(transferDto);
            return Response // 200
                    .ok(
                            new HashMap() {{
                                put("id", id);
                            }})
                    .build();
        } catch (Exception ex) {
            return Response // error 400
                    .status(400).entity(
                            new HashMap() {{
                                put("error", "failed to insert");
                            }})
                    .build();
        }
    }

}

Last step is configuring our database connection in application.properties file

quarkus.datasource.jdbc.url=jdbc:mysql://192.168.1.1:3306/db_test
quarkus.datasource.jdbc.driver=com.mysql.cj.jdbc.Driver
quarkus.datasource.jdbc.max-size=20
quarkus.datasource.jdbc.min-size=2

quarkus.datasource.username=root
quarkus.datasource.password=password

quarkus.hibernate-orm.database.generation=update

Finally, we can start our Quarkus app by running below command,

$ mvn compile quarkus:dev

And use curl to check whether API is accessible or not.

$ curl -L -X POST 'http://localhost:8080/transfer/' \
-H 'Content-Type: application/json' \
--data-raw '{
    "accountFrom":"4444",
    "accountTo": "55555",
    "amount" : 50000
}'

The full code for this can be accessed on below github link

https://github.com/edwin/quarkus-hello-world

Have fun with Quarkus 🙂

Error “Overriding bean of same name declared in: class path resource” when Integrating Spring Cloud Sleuth and ActiveMQ Library

Had this weird error when integrating ActiveMQ JMS and Spring Cloud Sleuth,

Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.jms.config.DefaultJmsListenerContainerFactory]: Factory method 'jmsListenerContainerFactory'
threw exception; nested exception is java.lang.IllegalStateException: @Bean method JMSReceiver.receiverActiveMQConnectionFactory called as bean reference for type [org.apache.activemq.ActiveMQConnectionFactory] but overridden by non-compatible bean instance of type [org.springframework.cloud.sleuth.instrument.messaging.LazyConnectionFactory].
Overriding bean of same name declared in: class path resource [id/co/edw/xxx/api/notificationengineservice/jmsClient/JMSReceiver.class]
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:185)
    at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:622)
    ... 27 common frames omitted
Caused by: java.lang.IllegalStateException: @Bean method JMSReceiver.receiverActiveMQConnectionFactory called as bean reference for type [org.apache.activemq.ActiveMQConnectionFactory]
but overridden by non-compatible bean instance of type [org.springframework.cloud.sleuth.instrument.messaging.LazyConnectionFactory]. Overriding bean of same name declared in:
class path resource [id/co/edw/xxx/api/notificationengineservice/jmsClient/JMSReceiver.class]
    at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.resolveBeanReference(ConfigurationClassEnhancer.java:418)
    at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:366)
    at id.co.edw.xxx.api.notificationengineservice.jmsClient.JMSReceiver$$EnhancerBySpringCGLIB$$10f22401.receiverActiveMQConnectionFactory(<generated>)
    at id.co.edw.xxx.api.notificationengineservice.jmsClient.JMSReceiver.jmsListenerContainerFactory(JMSReceiver.java:40)
    at id.co.edw.xxx.api.notificationengineservice.jmsClient.JMSReceiver$$EnhancerBySpringCGLIB$$10f22401.CGLIB$jmsListenerContainerFactory$1(<generated>)
    at id.co.edw.xxx.api.notificationengineservice.jmsClient.JMSReceiver$$EnhancerBySpringCGLIB$$10f22401$$FastClassBySpringCGLIB$$36560b20.invoke(<generated>)
    at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:244)
    at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:363)
    at id.co.edw.xxx.api.notificationengineservice.jmsClient.JMSReceiver$$EnhancerBySpringCGLIB$$10f22401.jmsListenerContainerFactory(<generated>)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:567)
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154)
    ... 28 common frames omitted

It happens because Spring Sleuth overriding bean provided by JMSReceiver,

package id.co.edw.xxx.api.notificationengineservice.jmsClient;
 
 
import org.apache.activemq.ActiveMQConnectionFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.jms.annotation.EnableJms;
import org.springframework.jms.config.DefaultJmsListenerContainerFactory;
 
import java.util.ArrayList;
import java.util.Arrays;
 
@Configuration
@EnableJms
public class JMSReceiver {
 
 
    @Value("somevalue")
    private String brokerUrl;
 
    @Bean
    @Primary
    public ActiveMQConnectionFactory receiverActiveMQConnectionFactory() {
        ActiveMQConnectionFactory activeMQConnectionFactory =
                new ActiveMQConnectionFactory();
        activeMQConnectionFactory.setBrokerURL(brokerUrl);
        activeMQConnectionFactory.setTrustedPackages(new ArrayList<>(Arrays.asList("id.co.edw.xxx.api,java.lang".split(","))));
 
 
        return activeMQConnectionFactory;
    }
 
    @Bean
    public DefaultJmsListenerContainerFactory jmsListenerContainerFactory() {
        DefaultJmsListenerContainerFactory factory =
                new DefaultJmsListenerContainerFactory();
        factory
                .setConnectionFactory(receiverActiveMQConnectionFactory());
        factory.setConcurrency("2");
 
        return factory;
    }
}

Problem solved after remarking Sleuth import on pom.xml,

<dependency>
	<groupId>javax.activation</groupId>
	<artifactId>javax.activation-api</artifactId>
</dependency>


<!--        <dependency>-->
<!--            <groupId>org.springframework.cloud</groupId>-->
<!--            <artifactId>spring-cloud-starter-sleuth</artifactId>-->
<!--            <version>2.1.2.RELEASE</version>-->
<!--        </dependency>-->


<dependency>
	<groupId>com.github.tomakehurst</groupId>
	<artifactId>wiremock-standalone</artifactId>
	<version>2.19.0</version>
	<scope>test</scope>
</dependency>

<!--     swaggwer -->
<dependency>
	<groupId>io.springfox</groupId>
	<artifactId>springfox-swagger2</artifactId>
	<version>2.9.2</version>
</dependency>

<!-- SMTP SPRING -->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-mail</artifactId>
</dependency>

<dependency>
	<groupId>javax.activation</groupId>
	<artifactId>javax.activation-api</artifactId>
</dependency>

A Simple Thousand Separator using Java

Trying to create a quick and simple solution for formatting an Integer into a formatted string with thousand separator,

	class Main
	{
		public static void main (String[] args) throws java.lang.Exception
		{
			String s = (String.format("%,d", 10000000)).replace(",",".");
			System.out.println(s);
		}
	}

The output will be, 10.000.000. (H)

How to Convert from a Point to a KML files and Generate a Circle with Radius on Each Point

Yesterday I got a challenging assignment to generate a telco network coverage map. But the only data i got is BTS (Base Transceiver Station) location, which is only latitude, longitude and coverage radius given on excel file. I need to convert those excel sheet data into a google map page, and displayed it to subscribers accordingly.

The biggest problem that i had is the number of data is quite big, i need to map more than 20k BTS location and need displayed it fast and without lagging. So a simple google maps script wont work because google maps have a limitation for this.

So i need to create a workaround, and after researching for quite some times i pick KML and Google FusionTable. KML data format for creating radius, and Google FusionTable for displaying it.

This is my PHP code for converting latitude, longitude and radius into KML code.

<?
$lats = array('4.53191944444444','5.34593888888889');
$longs = array('97.93600000000001','95.99299999999999');
$meter = 2000; 
 
$kml = '<?xml version="1.0" encoding="UTF-8"?><kml xmlns="http://www.opengis.net/kml/2.2" xmlns:atom="http://www.w3.org/2005/Atom"><Document>        
            <Style id="style0">
                    <LineStyle>
                      <color>ff000000</color>
                      <width>1</width>
                    </LineStyle>
                    <PolyStyle>
                      <color>7FAAAAAA</color>
                      <fill>1</fill>
                      <outline>1</outline>
                    </PolyStyle>               
            </Style>';

for($i = 0; $i < count($lats); $i++) {

    $lat = $lats[$i];
    $long = $longs[$i];

    // Get circle coordinates
    $coordinatesList = getCirclecoordinates($lat, $long, $meter);

    // Output
    $kml  .= '<Placemark><name>Circle '.$i.'</name><styleUrl>#style0</styleUrl><Polygon><outerBoundaryIs><LinearRing><coordinates>'.$coordinatesList.'</coordinates></LinearRing></outerBoundaryIs></Polygon></Placemark>';
}


$kml .= '</Document></kml>';
 
function getCirclecoordinates($lat, $long, $meter) {
  // convert coordinates to radians
  $lat1 = deg2rad($lat);
  $long1 = deg2rad($long);
  $d_rad = $meter/6378137;
 
  $coordinatesList = "";
  // loop through the array and write path linestrings
  for($i=0; $i<=360; $i+=3) {
    $radial = deg2rad($i);
    $lat_rad = asin(sin($lat1)*cos($d_rad) + cos($lat1)*sin($d_rad)*cos($radial));
    $dlon_rad = atan2(sin($radial)*sin($d_rad)*cos($lat1), cos($d_rad)-sin($lat1)*sin($lat_rad));
    $lon_rad = fmod(($long1+$dlon_rad + M_PI), 2*M_PI) - M_PI;
    $coordinatesList .= rad2deg($lon_rad).",".rad2deg($lat_rad).",0 ";
  }
  return $coordinatesList;
}

$fp = fopen('e:\lele.kml', 'w');
fwrite($fp, $kml);
fclose($fp);
?>

After KML is done, i just need to upload it to Google FusionTable and display it on my web page.
kmlcircle

Error java.sql.SQLException: Numeric Overflow when Connect to Oracle using Hibernate

Got weird error today, here is the complere stacktrace

2018-01-31 12:14:56 WARN  SqlException: - SQL Error: 17026, SQLState: 99999
2018-01-31 12:14:56 ERROR SqlException: - Numeric Overflow

Caused by: java.sql.SQLException: Numeric Overflow
	at oracle.jdbc.driver.NumberCommonAccessor.throwOverflow(NumberCommonAccessor.java:4136)
	at oracle.jdbc.driver.NumberCommonAccessor.getInt(NumberCommonAccessor.java:103)
	at oracle.jdbc.driver.GeneratedStatement.getInt(GeneratedStatement.java:197)
	at oracle.jdbc.driver.GeneratedScrollableResultSet.getInt(GeneratedScrollableResultSet.java:244)
	at oracle.jdbc.driver.GeneratedResultSet.getInt(GeneratedResultSet.java:554)
	at org.apache.tomcat.dbcp.dbcp.DelegatingResultSet.getInt(DelegatingResultSet.java:275)
	at org.apache.tomcat.dbcp.dbcp.DelegatingResultSet.getInt(DelegatingResultSet.java:275)
	at org.hibernate.type.descriptor.sql.IntegerTypeDescriptor$2.doExtract(IntegerTypeDescriptor.java:66)
	at org.hibernate.type.descriptor.sql.BasicExtractor.extract(BasicExtractor.java:64)
	at org.hibernate.type.AbstractStandardBasicType.nullSafeGet(AbstractStandardBasicType.java:265)
	at org.hibernate.type.AbstractStandardBasicType.nullSafeGet(AbstractStandardBasicType.java:261)
	at org.hibernate.type.AbstractStandardBasicType.nullSafeGet(AbstractStandardBasicType.java:251)
	at org.hibernate.type.AbstractStandardBasicType.hydrate(AbstractStandardBasicType.java:336)
	at org.hibernate.persister.entity.AbstractEntityPersister.hydrate(AbstractEntityPersister.java:2924)
	at org.hibernate.loader.Loader.loadFromResultSet(Loader.java:1695)
	at org.hibernate.loader.Loader.instanceNotYetLoaded(Loader.java:1627)
	at org.hibernate.loader.Loader.getRow(Loader.java:1509)
	at org.hibernate.loader.Loader.getRowFromResultSet(Loader.java:719)
	at org.hibernate.loader.Loader.processResultSet(Loader.java:949)
	at org.hibernate.loader.Loader.doQuery(Loader.java:917)
	at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:348)
	at org.hibernate.loader.Loader.doList(Loader.java:2550)
	... 75 more	

And here is my java class,

public class Class {
   private Integer value;

   // other setter and getter
}

How to solve the issue is actually quite simple, it’s all happen because im having a data on database which is bigger than Integer’s max value. Updating my bean from Integer to BigDecimal solve the problem,

public class Class {
   private BigDecimal value;

   // other setter and getter
}