Monday, January 11, 2016

HibenateTools and Oracle

1. If see this error as follows,

org.hibernate.cfg.jdbcbinder Exception and it says Duplicate class name 'Syscatalog' generated for 'org.hibernate.mapping.Table(SYS.SYSCATALOG_)'. Same name where generated for org.hibernate.mapping.Table(SYS.SYSCATALOG_)

just add property 'hibernate.default_schema' in hibernate.cfg.xml, for example,
 <property name="hibernate.default_schema">ABC</property>

2. configure @Id for oracle sequence

CREATE TABLE MY_TABLE(
    ID NUMBER NOT NULL,
    CONSTRAINT MY_TABLE_PK PRIMARY KEY(ID)
); 

CREATE SEQUENCE mytable_seq START WITH 1 INCREMENT BY 1 CACHE 10 NOCYCLE;

  @SequenceGenerator(name = "SEQGEN_MYTABLE", sequenceName = "mytable_seq",
      allocationSize = 1, initialValue = 1)
  @Id
  @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQGEN_MYTABLE")
  @Column(name = "ID")
  public long getId() {
    return this.id;

  }

Tuesday, October 13, 2015

spring boot, mockito, spring rest, junit

This is sample code to do junit test for spring rest/spring boot with mockito.

package com.demo.app.web.api.v1;

import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import com.demo.app.WebApplication;
import com.demo.app.repository.entity.Stock;
import com.demo.app.service.StockService;
import static org.hamcrest.Matchers.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;

@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@SpringApplicationConfiguration(classes = { WebApplication.class })
public class StockControllerTest {

private static final MediaType APP_ContentType = new MediaType(MediaType.APPLICATION_JSON.getType(),
MediaType.APPLICATION_JSON.getSubtype(), Charset.forName("utf8"));

private MockMvc mvc;

@Mock
private StockService stockService;

@InjectMocks
private StockController controller;

@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mvc = MockMvcBuilders.standaloneSetup(controller).build();
}

@After
public void tearDown() throws Exception {
}

@Test
public void testStocks() throws Throwable {

// prepare test data
List<Stock> stocks = new ArrayList<Stock>();
// stock1
Stock stock1 = new Stock();
stock1.setStockCode("code 1");
stock1.setStockName("name 1");
stock1.setStockPrice(1.111);
stock1.setStockPriceChange(-0.111);
stocks.add(stock1);
// stock2
Stock stock2 = new Stock();
stock2.setStockCode("code 2");
stock2.setStockName("name 2");
stock2.setStockPrice(2.222);
stock2.setStockPriceChange(-0.222);
stocks.add(stock2);
// stock3
Stock stock3 = new Stock();
stock3.setStockCode("code 3");
stock3.setStockName("name 3");
stock3.setStockPrice(3.333);
stock3.setStockPriceChange(-0.333);
stocks.add(stock3);

Mockito.when(stockService.findAll()).thenReturn(stocks);

mvc.perform(get("/api/v1/stocks")).andDo(print()).andExpect(MockMvcResultMatchers.status().isOk())
.andExpect(content().contentTypeCompatibleWith(APP_ContentType)).andExpect(jsonPath("$", hasSize(3)))
.andExpect(jsonPath("$[0].stockCode", is(stock1.getStockCode())))
.andExpect(jsonPath("$[0].stockName", is(stock1.getStockName())))
.andExpect(jsonPath("$[0].stockPrice", is(stock1.getStockPrice())))
.andExpect(jsonPath("$[0].stockPriceChange", is(stock1.getStockPriceChange())))
.andExpect(jsonPath("$[1].stockCode", is(stock2.getStockCode())))
.andExpect(jsonPath("$[1].stockName", is(stock2.getStockName())))
.andExpect(jsonPath("$[1].stockPrice", is(stock2.getStockPrice())))
.andExpect(jsonPath("$[1].stockPriceChange", is(stock2.getStockPriceChange())))
.andExpect(jsonPath("$[2].stockCode", is(stock3.getStockCode())))
.andExpect(jsonPath("$[2].stockName", is(stock3.getStockName())))
.andExpect(jsonPath("$[2].stockPrice", is(stock3.getStockPrice())))
.andExpect(jsonPath("$[2].stockPriceChange", is(stock3.getStockPriceChange())));

}

@Test
public void testGetStock() throws Throwable {

// prepare test data
Stock stock = new Stock();
stock.setStockCode("abc");
stock.setStockName("name 1");
stock.setStockPrice(1.111);
stock.setStockPriceChange(-0.111);

Mockito.when(stockService.findByStockCode(stock.getStockCode())).thenReturn(stock);

mvc.perform(get("/api/v1/stocks/{code}", stock.getStockCode())).andDo(print())
.andExpect(MockMvcResultMatchers.status().isOk())
.andExpect(content().contentTypeCompatibleWith(APP_ContentType))
.andExpect(jsonPath("$.stockCode", is(stock.getStockCode())))
.andExpect(jsonPath("$.stockName", is(stock.getStockName())))
.andExpect(jsonPath("$.stockPrice", is(stock.getStockPrice())))
.andExpect(jsonPath("$.stockPriceChange", is(stock.getStockPriceChange())));
}

}


=================== ==========================
with eclipse, if encounter this exception as follows,

java.lang.SecurityException: class "org.hamcrest.Matchers"'s signer information does not match signer information of other classes in the same package

open "Configure Build Path" and select "Library" tab, remove "Junit" from the build path. The root cause is jar conflict with plug in "Hamctest" inside eclipse.

Tuesday, September 22, 2015

Autowired not working for repository in spring boot

in spring boot, beside @SpringBootApplication, need to add the following 3 annotations to make @Autowired to init jpa repository objects.


@SpringBootApplication
@ComponentScan(basePackages = { "com.abc" })
@EnableJpaRepositories(basePackages = { "com.abc.repository" })
@EntityScan(basePackages = "com.abc.repository.entity")
public class WebApplication extends SpringBootServletInitializer {

@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(WebApplication.class);
}

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

Friday, January 9, 2015

Maven Jetty PermGen space

before run "mvn jetty:run"

run this command in window env

set MAVEN_OPTS=-Xmx1024m -XX:MaxPermSize=512m

or unix-like env
export MAVEN_OPTS="-Xmx1024m -XX:MaxPermSize=512m"

Friday, January 2, 2015

Spring MVC read properties in the class

This is sample code:

@Component( "emailService" )
public class EmailService {

  @Value( "${mail.server.url}" )
  private String url;

....
}

in the property file
mail.server.ur=http://abc/def


Monday, December 29, 2014

Android dev study notes - 1


  • Dailer
------ code snippet ------
       String number = tv.getText().toString();  // get No from an edittext
    Intent it = new Intent(Intent.ACTION_DIAL);
    it.setData(Uri.parse("tel:"+number));
    this.startActivity(it);

------- permission ------
<uses-permission android:name="android.permission.CALL_PHONE"/>
  • SMS
------ code snippet ------
        String mNo = evMobileNo.getText().toString();
String content = evSMSContent.getText().toString();
SmsManager sm = SmsManager.getDefault();
ArrayList<String> text = sm.divideMessage(content);  // just in case message is too long
for (String s : text) {
sm.sendTextMessage(mNo, null, s, null, null);
}
Toast.makeText(MainActivity.this, "sent success",
Toast.LENGTH_LONG).show();

------- permission ------
 <uses-permission android:name="android.permission.SEND_SMS" />
  • Save/Read File to/from memory card

public void savePrivateMode(String fileName, String fileContent)
throws Exception {
FileOutputStream out = context.openFileOutput(fileName,
Context.MODE_PRIVATE);
out.write(fileContent.getBytes());
out.close();
}

The mode is Context.MODE_PRIVATE, only the app who created the file is allowed to access the file, no one else is allowed to access it.
The file permission is -rw-rw----
If save the same file name again and again, the content will be overwrited.

And the location of this file is /data/data/<app package name>/files/<file name> in the memory card.

public void saveAppendMode(String fileName, String fileContent)
throws Exception {
FileOutputStream out = context.openFileOutput(fileName,
Context.MODE_APPEND);
out.write(fileContent.getBytes());
out.close();
}

The mode is Context.MODE_APPEND, only the app who created the file is allowed to access the file, no one else is allowed to access it.
The file permission is -rw-rw----
If save the same file name again and again, the content will be appended.

And the location of this file is /data/data/<app package name>/files/<file name> in the memory card.

public String read(String fileName) throws Exception {
FileInputStream input = context.openFileInput(fileName);
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len = 0;
while ((len = input.read(buffer)) != -1) {
out.write(buffer, 0, len);
}
                // omit i/o close() method
return new String(out.toByteArray());
}

This method is allowed to read file under  /data/data/<app package name>/files/<file name> at the same app.

If another app needs to access this file in this app, the code is as follows,

public String read(String fileName) throws Exception {
                String fn = "/data/data/<package name>/files/"+fileName;
                File file = new File(fn);
                // should NOT be  context.openFileInput(fileName); it is for memory card
FileInputStream input = new FileInputStream(file);
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len = 0;
while ((len = input.read(buffer)) != -1) {
out.write(buffer, 0, len);
}
                // omit i/o close() method
return new String(out.toByteArray());
}

If the mode is Context.MODE_PRIVATE or Context.MODE_APPEND, cannot read file from external app, unless the external app set the mode as Context.MODE_WORLD_READABLE when saving the file.
If an app is open the file to be read/write for external apps, when save a file, the file mode need to set as Context.MODE_WORLD_READABLE + Context.MODE_WORLD_WRITEABLE


  • Save/Read File to/from SD card
before read/write file to/from SD card, need to check the card is available or not by the following,

if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))

file location:
File file = new File(Environment.getExternalStorageDirectory(),fileName);

Enviroment.getExternalStorageDirectory() points to /mnt/sdcard for current android os, and points to /sdcard for very older os version.
  • SharedPreferences
let's say user chooses preferred color and font size for UI setting, then save such info to SharedPreferences.

public void save(String color, int fontSize) {
SharedPreferences sf = context.getSharedPreferences("custprefer",
Context.MODE_PRIVATE);
Editor edit = sf.edit();
edit.putString("color", color);
edit.putInt("fontSize", fontSize);
edit.commit();
}

in the end, a new file custprefer.xml will be generated at folder /data/data/<package>/shared_prefs/custprefer.xml  as follows,

<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
<int name="fontSize" value="12" />
<string name="color">red</string>
</map>

  • SQLite
package com.example.dbdemo;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

public class DBHelper extends SQLiteOpenHelper {

public DBHelper(Context context) {
super(context, "demo.db", null, 1);
}

@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("create table person(pid integer primary key autoincrement,name varchar(20))");
}

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

}

}

From the constructor, set db version is 1, and db file name is demo.db, onCreate() will be triggered if demo.db does not exit.

This is a test class to trigger onCreate() method.
package com.example.dbdemo.test;

import com.example.dbdemo.DBHelper;

import android.test.AndroidTestCase;

public class DBHelperTester extends AndroidTestCase {

public void testDB() throws Exception {
DBHelper helper = new DBHelper(this.getContext());
helper.getWritableDatabase();
}
}

then the new demo.db file will be found in folder /data/data/<package>/databases/demo.db, use the tools sqlite expert to check the table is created successfully.

Now change above code to make the version to 2 in the constructor,and add some db changes in method onUpgrade() which will be triggered if db version changes

package com.example.dbdemo;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

public class DBHelper extends SQLiteOpenHelper {

public DBHelper(Context context) {
super(context, "demo.db", null, 2);
}

@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("create table person(pid integer primary key autoincrement,name varchar(20))");
}

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("create table teacher(tid integer primary key autoincrement,name varchar(20))");
db.execSQL("alter table person add address varchar(20) null");
}

}

run above test method again, found a new table and a new field are created.

This is a simple class to insert a record

public class MyDbService {

private DBHelper dbHelper;

public MyDbService(DBHelper dbHelper) {
this.dbHelper = dbHelper;
}

public void save() {
SQLiteDatabase db = dbHelper.getWritableDatabase();
db.execSQL("insert into person (name) values (?)",
new Object[] { "testuser" });
}
}
  • TBC

Spring MVC restful tips - 406 error, cannot put email in the url


  • 406 not acceptable error

need to add the following configuration

<mvc:annotation-driven
content-negotiation-manager="contentNegotiationManager">
</mvc:annotation-driven>

<bean id="contentNegotiationManager"
class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
<property name="favorPathExtension" value="false" />
<property name="favorParameter" value="true" />
<property name="mediaTypes">
<value>
json=application/json
xml=application/xml
</value>
</property>
</bean>
<!-- resolve not acceptable issue -->
<bean id="jacksonMessageConverter"
class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>text/html;charset=UTF-8</value>
<value>text/xml;charset=UTF-8</value>
<value>application/json;charset=UTF-8</value>
</list>
</property>
</bean>

this is jackson dependencies:
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-core-asl</artifactId>
<version>${jackson.version}</version>
</dependency>

<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>${jackson.version}</version>
</dependency>


<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.6</maven.compiler.source>
<maven.compiler.target>1.6</maven.compiler.target>
<spring.core.version>3.2.4.RELEASE</spring.core.version>
<log.version>1.2.17</log.version>
<hibernate.version>3.6.10.Final</hibernate.version>
<jackson.version>1.9.13</jackson.version>
</properties>


  • avoid URI using dots to be truncated
  @RequestMapping( value = "/users/{email:.+}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE )