Monthly Archives: June 2019

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}>
                        <CssBaseline/>
                        <p>Some content</p>
                    </MuiThemeProvider>
                );
        
    }
}



Code snippet: Swagger + Spring Boot

compile 'io.springfox:springfox-swagger2:2.9.2'
compile 'io.springfox:springfox-swagger-ui:2.9.2'
/**
 See https://www.baeldung.com/swagger-2-documentation-for-spring-rest-api
 */
 @Configuration
 @EnableSwagger2
 public class SwaggerConfig {
 @Value("${enable.swagger}")  //You may want to disabled it in PROD
 boolean enableSwagger;
 @Bean
 public Docket api() {
     Docket api = new Docket(DocumentationType.SWAGGER_2)
             .select()
             .apis(RequestHandlerSelectors.basePackage("your.package"))
             .paths(PathSelectors.any())
             .build();
        ApiInfo apiInfo = new ApiInfoBuilder()		
                .version("xxx")
                .description("xxx")
                .termsOfServiceUrl("xxx")
                .title("Xxx Doc")
                .build();

        api.useDefaultResponseMessages(false).apiInfo(apiInfo);

        api.enable(enableSwagger);

        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: https://flyingsaucerproject.github.io/flyingsaucer/r8/guide/users-guide-R8.html#xil_6
  • 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:

<head>
    <style>
        @page {
            margin-left: 9px;   /* about 0.1 inch */ 
            margin-right: 9px; 
            size: A4;
        }
    </style>
   ...

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 https://stackoverflow.com/a/35641992/301447 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 https://github.com/reduxjs/redux/issues/992#issuecomment-167964652
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,
    applyMiddleware(thunkMiddleware,
        typedActionToPlain //this must be after thunk, otherwise it will try to convert an async function to a plain object
    )
);

Gradle upload a custom-generated jar file to Nexus

Do this:

apply plugin: 'maven-publish'


   publishing {
        publications {
            maven( MavenPublication ) {
                artifact theTaskThatGeneratesJar
            }
        }
        repositories {
            maven {
                def releasesRepoUrl = http://.../repositories/releases/'
                def snapshotsRepoUrl = 'http://.../repositories/snapshots/'
                url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl
                credentials {
                    username 'xxx'
                    password 'xxx'
                }
            }
        }

    }