Tuesday, January 30, 2018

Android - Fix gradle Could not initialize class AndroidSdkHandler

Fix gradle Could not initialize class AndroidSdkHandler

I have Java 8 and 9 installed on my machine, I did not have problems until one day I tried to run gradle command. I google for the answer of course, some suggested to remove Java 9. But I did not like to mess up the system by installing/uninstalling software. So I changed JAVA_HOME to point java 8, and the problem solved.

Environment

  • macOS

Fix

JAVA_HOME was set to point to the latest Java in ~/.bash_profile

export JAVA_HOME=$(/usr/libexec/java_home)
# java -version
java version "9.0.1"
Java(TM) SE Runtime Environment (build 9.0.1+11)
Java HotSpot(TM) 64-Bit Server VM (build 9.0.1+11, mixed mode)

Gradle throws error
* What went wrong:
A problem occurred configuring project ':app'.
> Failed to notify project evaluation listener.
   > Could not initialize class com.android.sdklib.repository.AndroidSdkHandler

Change JAVA_HOME to point to Java 8

export JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_151.jdk/Contents/Home

To view the specific version of Java installed, look the directory /Library/Java/JavaVirtualMachines/

# source ~/.bash_profile
# java -version
java version "1.8.0_151"
Java(TM) SE Runtime Environment (build 1.8.0_151-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.151-b12, mixed mode)

Friday, November 10, 2017

Spring framework - Jackson UnrecognizedPropertyException not thrown

Jackson UnrecognizedPropertyException not thrown

This post is to show how to force newer version of Spring (4.1.1.RELEASE and later) to return error when a JSON with unrecognized fields is deserialized.

Setup

Maven
<dependency>
 <groupId>org.springframework</groupId>
 <artifactId>spring-core</artifactId>
 <version>4.3.12.RELEASE</version>
</dependency>
<dependency>
 <groupId>org.springframework</groupId>
 <artifactId>spring-webmvc</artifactId>
 <version>4.3.12.RELEASE</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.9.2</version>
</dependency>

Development

User.java

package com.example.model;

public class User {
    private String id;
    private String name;

    // constructor, setters, getters
}

JSON

{
  “id”: “28b60d1e-c650-11e7-abc4-cec278b6b50a”,
  “name”: “John Smith”,
  “nickname”: “Johnny”
}

Controller.java

package com.example.controller;

@RestController
public class Controller {

    private UserService userService;

    @PutMapping(“/user”)
    public void updateUserInfo(@RequestBody User user) {
        userService.updateUser(user);
    }
}
I expected to see UnrecognizedPropertyException or 400 Bad Request when the JSON was sent in, but it did not happen. Adding the annotation @JsonIgnoreProperties(ignoreUnknown=false) to the POJO had no effect, either. It turns out Spring Framework has changed its default configuration. So in the Spring configuration xml, I have to override its behavior

context-config.xml

<mvc:annotation-driven">
 <mvc:message-converters>
  <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
              <property name="objectMapper">
               <bean class="com.fasterxml.jackson.databind.ObjectMapper"/>
              </property>
  </bean>
 </mvc:message-converters>
</mvc:annotation-driven>

Tuesday, September 26, 2017

Android - set host IP on app

Android - dynamic host IP

I want to test my Android RESTful API requests against the mock web server running on the same PC. The PC has dynamically assigned IP address, so the mock web server might also have different IP address when I restart the server. I could manually change the server IP on Android source code when new IP is assigned, but it’s not practical because not only do I modify the source code, it will also block the tests on daily build machine. The code snippet is to demonstrate how to dynamically set the host IP address on Android.

Setup

  • Android Studio

Development

build.gradle

android {
    . . .
    buildTypes {
        debug {
            buildConfigField "String", "SERVER_ADDR", '\"' + getHostIp() + '\"'
        }
        release {
            . . .
        }
    }
}

def getHostIp() {
    String result = "127.0.0.1";
    Enumeration ifaces = NetworkInterface.getNetworkInterfaces();
    while (ifaces.hasMoreElements()) {
        NetworkInterface iface = ifaces.nextElement();
        if (!iface.isLoopback()) {
            for (InterfaceAddress ifaceAddr : iface.getInterfaceAddresses()) {
                if (ifaceAddr.getAddress().isSiteLocalAddress()) {
                    result = ifaceAddr.getAddress().getHostAddress();
                    break;
                }
            }
        }
    }
    return result;
}

Now the host IP can be obtained from SERVER_ADDR

package com.example;

import static com.example.test.BuildConfig.SERVER_ADDR;

@RunWith(AndroidJUnit4.class)
public class RESTApiTest {
    private final static String MOCK_SERVER = "http://" + SERVER_ADDR + “:5438/API/v1.0/“;

    @Test
    Public void testHelloWorld {
        . . .
    }
}

In case you are running the tests on an actual device, make sure the device is also running on the same subnet.

Monday, July 11, 2016

Spring framework - Strange characters in Spring writing key to redis

Strange characters in Spring writing key to redis

With the redisTemplate bean declared, Spring is ready to manipulate data on redis

<bean id="redisTemplate" 
     class="org.springframework.data.redis.core.RedisTemplate" 
     p:connection-factory-ref="jedisConnectionFactory"/>

But after the key is set from Spring, you will see the addition strange characters like to “\xac\xed\x00\x05t\x00\t” prepended to the key on redis

redis> keys *
"\xac\xed\x00\x05t\x00\takey"

To get rid of that, create a redis serializer bean

<bean id="stringRedisSerializer" 
     class="org.springframework.data.redis.serializer.StringRedisSerializer"/>

and inject it to keySerializer in redisTemplate.

<bean id="redisTemplate" 
     class="org.springframework.data.redis.core.RedisTemplate" 
     p:connection-factory-ref="jedisConnectionFactory"
     p:keySerializer-ref="stringRedisSerializer"/>

so that the key will not have the unwanted characters.

The values still have them

Without configuring value serializer, the extra characters may not affect the output of reading values. But it will cause “redis.clients.jedis.exceptions.JedisDataException: ERR hash value is not an integer” if you try to do HashOperations.increment(H key, HK hashKey, long delta). That’s because the value is not a number and the operation tries to increment the number before deserialization. In order to for increment() work properly, it’s necessary to inject the redis serializer with Long class to valueSerializer in redis template

<bean id="longRedisSerializer" class="org.springframework.data.redis.serializer.GenericToStringSerializer">
    <constructor-arg type="java.lang.Class" value="java.lang.Long"/>
</bean>

for Sets

<bean id="longRedisTemplate"
     class="org.springframework.data.redis.core.RedisTemplate"
     p:connection-factory-ref="jedisConnectionFactory"
     p:keySerializer-ref="stringRedisSerializer"
     p:valueSerializer-ref="longRedisSerializer"/>

for Hashes

<bean id="longRedisTemplate"
     class="org.springframework.data.redis.core.RedisTemplate"
     p:connection-factory-ref="jedisConnectionFactory"
     p:keySerializer-ref="stringRedisSerializer"
     p:hashKeySerializer-ref="stringRedisSerializer"
     p:hashValueSerializer-ref="longRedisSerializer"/>

References

  1. Weird redis key with spring data Jedis
  2. spring-data-redis redisTemplate Excetion

Friday, February 27, 2015

CRC32 calculation on Java and Objective-C

CRC32.md

One time I had to calculate CRC32 checksum for image files on Java and Objective-C. But I could not get the results matched when I tried to read the file via UIImagePickerController on Objective-C. I knew the result from Java was correct because this website returned the same checksum. The myth was finally resolved when I loaded the file from resource by using NSBundle.

Source code

code snippet in Java

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.zip.CRC32;

...
try {
    Path path = Paths.get("path/to/image.jpg");
    byte[] data = Files.readAllBytes(path);
    Checksum checksum = new CRC32();
    checksum.update(data, 0, data.length);
    long result = checksum.getValue();
    System.out.println("file crc32 cheksum: " + result);
} catch (IOException e){
    e.printStackTrace();
}

code snippet in Objective-C

you will need to add libz.dylib in Linked Frameworks and Libraries in General tab on Xcode.

#include <zlib.h>;

...
NSString *filePath = [[NSBundle mainBundle] pathForResource:@"image" ofType:@"jpg"];
NSData *data = [NSData dataWithContentsOfFile:filePath];
uLong crc = crc32(0L, Z_NULL, 0);
long long result = crc32(crc, [data bytes], [data length]);
NSLog(@"file crc32 checksum %llu", result));

Tuesday, February 10, 2015

Create executable jar on Eclipse

1. After the coding is complete, run the project as Java Application. This step is mandatory for Eclipse to create the Launch configuration info.

2. Identify the Launch configuration name by going to "Run Configurations..." (right click on project -> Run As). On the "Main" tab, there is a Name textbox on the top. The value is editable.

3. Export the project as "Runnable JAR file" (Right click on project -> Export). On the next step, select the Launch configuration for the name and set the Export destination.

4. After the jar is generated, run the application by java -jar <app_name.jar>

Monday, January 12, 2015

The Hello World JNI example

The Hello World JNI example

A simple example to use native code (C/C++ in this tutorial) via JNI (Java Native Interface). The Java program will take the input from user, and then pass the value to native code to print out on console.

Setup

  • Linux Mint - a modern, elegant and comfortable Linux distro
  • OpenJDK - the JDK on Linux Mint
  • gcc - the c compiler

Installation

Make usre the software is installed properly

$ javac -version
javac 1.7.0_75
$ gcc --version
gcc (Ubuntu 4.8.2-19ubuntu1) 4.8.2
...

Development

Demo.java

package com.example.jni;

public class Demo {

    // load native library at runtime
    static {
        System.loadLibrary("myNative");
    }

    // declare a native method
    public native void helloNative(String message);

    public static void main(String[] args) {
        new Demo().helloNative(args[0]);
    }
}

generate the header file com_example_jni_Demo.h

path/to/java/src $ javah com.example.jni.Demo

no need to modify the header file, but it declares the method to implement

JNIEXPORT void JNICALL Java_com_example_jni_Demo_helloNative
  (JNIEnv *, jobject, jstring);

myNative.c

#include 
#include "com_example_jni_Demo.h"

JNIEXPORT void JNICALL Java_com_example_jni_Demo_helloNative(JNIEnv *env, jobject obj, jstring javaString)
{
    const char *message;
    message = (*env)->GetStringUTFChars(env, javaString, 0);
    printf("native echo: %s\n", message);
}

generate the Shared Library which will be libmyNative.so

path/to/java/src $ gcc -shared -fPIC -o libmyNative.so -I /usr/lib/jvm/java-7-openjdk-amd64/include -I /usr/lib/jvm/java-7-openjdk-amd64/include/linux myNative.cdino

compile and run the program

path/to/java/src $ javac com/example/jni/Demo.java
path/to/java/src $ java -Djava.library.path=path/to/java/src Demo

To run the Java program on Eclipse, add -Djava.library.path=path/to/shared/library to Run configurations -> Arguments -> VM arguments