Author Archives: Chen Jian

IOS Safari showing a blank page when coming back to a React Component


When you go to a react component, then go to another, and finally come back, the react component is showing blank, or half-blank.


If you inspect the page with the mobile safari inspector , you can see the elements are there, but safari just refuse to show the data on the screen.

In my case, this seems to be related with data reloading when I come back to the component. It reloads the data in its componentDidAmount() then re-render. Safari may not perform well enough to handle this kind of re-rendering.


A workaround is to not reload the data when you come back to the component. You can do this by checking if the data exists, and only loads the data if not existing.

It comes with a price: when you come back to the component, you are not seeing the data that’s up-to-data. There are a few things you can do to make it up:

  • A delayed data re-loading
  • Always reload the data 24 hours (e.g.) after last data loading
  • Very important: destroy the data if a user logs out to make sure a different user won’t see the first user’s data

Jetty’s start.jar forks a new JVM to run the app if logback module is enabled

Jetty is too smart. If there is any JVM option provided, Jetty will spawn a new JVM instance to do the real work, even if you don’t use “–exec” option in start.ini

And jetty’s logback module introduces a JVM option. See here

You will see:


So does it matter?

It matters a lot because all the JVM options you passed to start.jar will stay on the process of start.jar. They are not passed to the forked JVM process.

What’s the solution ?

Since you have to let it fork a new JVM because of logback, you can just put all the JVM options in start.ini. Like,


Miscellaneous tips while developing in WSL (Windows Subsystem for Linux)

File change monitoring doesn’t work, such as the auto-refresh of create-react-app

Use the following before your "npm start" or put it on env file:


And if you are using Intellij, you need to explicitly "ctrl + s" to save the changes on your code files

Integrate beyond compare with git diff

export TMPDIR='/mnt/c/Users/yourName/AppData/Local/Temp'
alias gitdiff='git difftool -y --no-symlinks &'
#In your ~/.gitconfig  , add the following

            tool = BCompare
[difftool "BCompare"]
            path = "/mnt/c/Program Files/Beyond Compare 4/BCompare.exe"
            cmd = \"/mnt/c/Program Files/Beyond Compare 4/BCompare.exe\" -expandall \"`echo $LOCAL | sed 's_/mnt/c_C:_'`\" \"`echo $REMOTE | sed 's_/mnt/c_C:_'`\"

To run it,

$ gitdiff

Install terminator

Click here

Change the font family globally in Material-UI 3.x

Some say you should use the jsx-global-plugin like “@global body{fontFamily:’someFont’}” , but it doesn’t work in my project. The global CSS still has the lower CSS speciality than MUI components’ CSS because this global CSS is using a type selector.

You should use a theme instead

//create a theme 

const myTheme = createMuiTheme({
    typography: {
        fontFamily: "Roboto Condensed" 

// use the theme

class MyComponent extends React.Component<Props> {

    render() {
            return (
                    <MuiThemeProvider theme={this.props.theme}>
                        <p>Some content</p>

Code snippet: Swagger + Spring Boot

compile 'io.springfox:springfox-swagger2:2.9.2'
compile 'io.springfox:springfox-swagger-ui:2.9.2'
 public class SwaggerConfig {
 @Value("${enable.swagger}")  //You may want to disabled it in PROD
 boolean enableSwagger;
 public Docket api() {
     Docket api = new Docket(DocumentationType.SWAGGER_2)
        ApiInfo apiInfo = new ApiInfoBuilder()		
                .title("Xxx Doc")



        return api;

Generate PDF from server side using Java

You can use OpenPDF to draw a PDF (the open source fork of iText). However, the learning curve of creating PDF with layouts and stuff is very high.

A more cost-effective solution is create an HTML version of it and convert it using Flying Saucer with its OpenPDF component

. As a Java developer you are already familiar with html + css, so doing that is quick.

There are some limitations and side effects of this approach

  • Your html must be XML/XHTML
  • Styles’ version must be no more than CSS 2.1. (So you can’t use flexbox layout)
  • No javascript
  • More:
  • The image quality seems worse than what you see on the html page, if there is any

And to create a PDF, your html can’t be too wide, otherwise content may be lost.

Typically, say you are creating an A4 PDF with margin of 0.1 inch on both left and right, the width of your html should not be more than (A4’s paper width – margin) * pixe density = (8.27inch – 0.1 inch * 2) * 96 DPI = 774 pixels

And here is how to set up the size and margin of the PDF in your html:

        @page {
            margin-left: 9px;   /* about 0.1 inch */ 
            margin-right: 9px; 
            size: A4;

Redux + Typescript: The type of the root state

You can get the type of the state from the root reducer

// the reducer
const appReducer = combineReducers({
    global: globalStateReducer,
    example: exampleReducer

type AppState = ReturnType<typeof appReducer>

However the redux state can be cleared in some scenarios, so it should be undefinable

//See for "undefined redux state" 
type RootState = AppState | undefined;

const rootReducer = (state:RootState, action: Action) => {
    if (action.type === DESTROY_REDUX_STATE) {
        state = undefined;
    return appReducer(state, action)

And mapStateToProps() of a component will look like this:

function mapStateToProps(rootState: RootState) {
    return {
        example: rootState!.example  //note the exclamation mark as rootState can be undefined 

Redux + Typescript: Use class to define Actions

You want the actions to be typed. You should use interface or class.

Class is better than interface because in interfaces you cannot define the action "type" as a constant, but in classes you can:

class LoadingStartedAction implements Action{
    readonly type = LOADING_STARTED

However a class instance is not a plain object, but Redux requires plain objects to be dispatched.

This can be handled by a middleware which converts the class instances to plain objects

// See
const typedActionToPlain = (store: any) => (next: any) => (action: any) =>  {
    next(Object.assign({}, action));

export default typedActionToPlain;

Pay attention not to step into the toe of Thunk middleware when registering it:

const rootStore = createStore(rootReducer,
        typedActionToPlain //this must be after thunk, otherwise it will try to convert an async function to a plain object

Read process output in Java without hanging the main thread

 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.


 * @author chenjianjx (Copied from CXF)
public class StreamPrinter extends Thread {
  InputStream is;
  String msg;
  OutputStream os;

  public StreamPrinter(InputStream stream, String type) {
    this(stream, type, null);

  public StreamPrinter(InputStream stream, String type, OutputStream redirect) {
    is = stream;
    msg = type;
    os = redirect;

  public void run() {
    try {
      PrintWriter pw = null;
      if (os != null) {
        pw = new PrintWriter(os);
      InputStreamReader isr = new InputStreamReader(is);
      BufferedReader br = new BufferedReader(isr);
      String line = br.readLine();
      while (line != null) {
        if (pw != null) {
          pw.println(msg + " " + line);
        line = br.readLine();
      if (pw != null) {
    } catch (IOException ioe) {
      throw new RuntimeException(ioe);
 * @author chenjianjx

public class SystemProcessException extends Exception {

  private int returnCode;
  private String consoleOutput;

  private static final long serialVersionUID = -6904952219344675845L;

  public SystemProcessException(int returnCode, String consoleOutput) {
    this.returnCode = returnCode;
    this.consoleOutput = consoleOutput;

  public int getReturnCode() {
    return returnCode;

  public String getConsoleOutput() {
    return consoleOutput;



 * Spawning a process from the OS
 * @author chenjianjx
public class SystemProcessUtils {

   * execture a program and returns console output
  public static String exec(String[] cmdArray) throws SystemProcessException {

    try {
      Process p = Runtime.getRuntime().exec(cmdArray);
      ByteArrayOutputStream output = new ByteArrayOutputStream();
      Thread errStreamThread = collectErrorStream(p, output);
      Thread inputStreamThread = collectInputStream(p, output);
      int returningCode = p.waitFor();
      int timeout = 60000;
      if (errStreamThread != null) {
      if (inputStreamThread != null) {
      String consoleOutput = new String(output.toByteArray());
      if (returningCode != 0) {
        throw new SystemProcessException(returningCode, consoleOutput);
      return consoleOutput;
    } catch (IOException e) {
      throw new IllegalStateException(e);
    } catch (InterruptedException e) {
      throw new IllegalStateException(e);

  private static StreamPrinter collectInputStream(Process p, OutputStream out) {
    if (p.getInputStream() != null) {
      StreamPrinter infoStreamPrinter = new StreamPrinter(p.getInputStream(), "[INFO]", out);
      return infoStreamPrinter;
    return null;

  private static StreamPrinter collectErrorStream(Process p, OutputStream out) {
    if (p.getErrorStream() != null) {
      StreamPrinter errorStreamPrinter = new StreamPrinter(p.getErrorStream(), "[ERROR]", out);
      return errorStreamPrinter;
    return null;