org.jberet.support.io.JsonItemReaderTest.java Source code

Java tutorial

Introduction

Here is the source code for org.jberet.support.io.JsonItemReaderTest.java

Source

/*
 * Copyright (c) 2014 Red Hat, Inc. and/or its affiliates.
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 * Cheng Fang - Initial API and implementation
 */

package org.jberet.support.io;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.io.Writer;
import java.lang.reflect.Type;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.TimeUnit;
import javax.batch.operations.JobOperator;
import javax.batch.runtime.BatchRuntime;
import javax.batch.runtime.BatchStatus;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.io.IOContext;
import com.fasterxml.jackson.core.io.InputDecorator;
import com.fasterxml.jackson.core.io.OutputDecorator;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.deser.DeserializationProblemHandler;
import org.jberet.runtime.JobExecutionImpl;
import org.junit.Assert;
import org.junit.Test;

/**
 * A test class that reads json resource into java object and write out to json format.
 */
public final class JsonItemReaderTest {
    static final String jobName = "org.jberet.support.io.JsonItemReaderTest";
    private final JobOperator jobOperator = BatchRuntime.getJobOperator();
    static final String movieJson = "movies-2012.json";
    static final String movieJsonUnknownProperty = "movies-2012-unknown-properties.json";
    static final String widgetJson = "widget.json";
    static final String githubJson = "https://api.github.com/users/chengfang/repos";

    static final String widgetExpect1 = "\"widget\", \"debug\", \"window\", \"title\", "
            + "\"Sample Konfabulator Widget\", \"name\", \"main_window\", \"width\","
            + "500, \"height\", \"image\", \"src\", \"Images/Sun.png\", \"sun1\", \"hOffset\", 250,"
            + "\"vOffset\", \"alignment\", \"center\", \"text\", \"data\", \"Click Here\", \"size\","
            + "36, \"style\", \"bold\", \"text1\", \"onMouseUp\", "
            + "\"sun1.opacity = (sun1.opacity / 100) * 90;\"";
    static final String widgetExpect2 = "\"Two Widget\", \"two_window\", \"Images/Two.png\"";
    static final String widgetExpect3 = "\"Three Widget\", \"three_window\", \"Images/Three.png\"";
    static final String widgetForbidFrom1 = "Sample Konfabulator Widget, main_window, Images/Sun.png";

    private String jsonGeneratorFeatures;
    private String deserializationProblemHandlers;
    private String customDataTypeModules;

    //https://issues.jboss.org/browse/JBERET-44
    //no transaction started after a chunk where no data is written.
    //the ItemProcessor in this test is configured to filter out all items so there is always no data to write out.
    //when a new chunk is started, TransactionManager should also begin a new tx.
    @Test
    public void testMovieFilterProcessor() throws Exception {
        final String filtering = "filtering";
        System.setProperty(filtering, "true");
        testReadWrite0(movieJson, "testMovieFilterProcessor.out", "1", "15", Movie.class, null, null,
                BatchStatus.COMPLETED);
        System.clearProperty(filtering);
    }

    @Test
    public void testBeanTypeGithubJson1_999() throws Exception {
        testReadWrite0(githubJson, "testBeanTypeGithubJson1_999.out", "1", "999", GithubData.class, null, null,
                BatchStatus.COMPLETED);
    }

    @Test
    public void testBeanTypeGithubJson1() throws Exception {
        testReadWrite0(githubJson, "testBeanTypeGithubJson1.out", "1", "1", GithubData.class, null, null,
                BatchStatus.COMPLETED);
    }

    @Test
    public void testBeanTypeGithubJson2_3() throws Exception {
        testReadWrite0(githubJson, "testBeanTypeGithubJson2_3.out", "2", "3", GithubData.class, null, null,
                BatchStatus.COMPLETED);
    }

    @Test
    public void testNodeTypeGithubJson() throws Exception {
        testReadWrite0(githubJson, "testNodeTypeGithubJson.out", null, null, JsonNode.class, null, null,
                BatchStatus.COMPLETED);
    }

    @Test
    public void testBeanType2_4() throws Exception {
        jsonGeneratorFeatures = " QUOTE_FIELD_NAMES = false , STRICT_DUPLICATE_DETECTION = false";

        //rating enum is written out as index, as configured in job xml serializationFeatures property
        //final String forbid = MovieTest.forbid2_4 + ", \"rank\", \"tit\", \"grs\", \"opn\", PG13";
        final String forbid = MovieTest.forbid2_4 + ", PG13";
        testReadWrite0(movieJson, "testBeanType2_4.out", "2", "4", Movie.class, MovieTest.expect2_4, forbid,
                BatchStatus.COMPLETED);
        jsonGeneratorFeatures = null;
    }

    @Test
    public void testJsonNodeType2_4() throws Exception {
        testReadWrite0(movieJson, "testJsonNodeType2_4.out", "2", "4", JsonNode.class, MovieTest.expect2_4,
                MovieTest.forbid2_4, BatchStatus.COMPLETED);
    }

    @Test
    public void testBeanTypeFull() throws Exception {
        testReadWrite0(movieJson, "testBeanTypeFull.out", null, null, Movie.class, MovieTest.expectFull, null,
                BatchStatus.COMPLETED);
    }

    @Test
    public void testBeanTypeJodaFull() throws Exception {
        customDataTypeModules = "com.fasterxml.jackson.datatype.joda.JodaModule, com.fasterxml.jackson.datatype.jdk7.Jdk7Module";
        testReadWrite0(movieJson, "testBeanTypeJodaFull.out", null, null, MovieWithJoda.class, MovieTest.expectFull,
                null, BatchStatus.COMPLETED);
        customDataTypeModules = null;
    }

    @Test
    public void testMapTypeFull1_100() throws Exception {
        testReadWrite0(movieJson, "testMapTypeFull1_100.out", "1", "100", Map.class, MovieTest.expectFull, null,
                BatchStatus.COMPLETED);
    }

    @Test
    public void testJsonMapType1_2() throws Exception {
        testReadWrite0(movieJson, "testJsonMapType1_2.out", "1", "2", Map.class, MovieTest.expect1_2,
                MovieTest.forbid1_2, BatchStatus.COMPLETED);
    }

    @Test
    public void testJsonNodeTypeWidget1() throws Exception {
        testReadWrite0(widgetJson, "testJsonNodeTypeWidget1.out", "1", "1", JsonNode.class, widgetExpect1,
                widgetExpect2, BatchStatus.COMPLETED);
    }

    @Test
    public void testJsonNodeTypeWidget1_3() throws Exception {
        testReadWrite0(widgetJson, "testJsonNodeTypeWidget1_3.out", "1", "3", JsonNode.class,
                widgetExpect1 + ", " + widgetExpect2 + ", " + widgetExpect3, null, BatchStatus.COMPLETED);

        testReadWrite0(widgetJson, "testJsonNodeTypeWidget1_3.out", null, null, JsonNode.class,
                widgetExpect1 + ", " + widgetExpect2 + ", " + widgetExpect3, null, BatchStatus.COMPLETED);
    }

    @Test
    public void testMapTypeWidget2_3() throws Exception {
        testReadWrite0(widgetJson, "testMapTypeWidget2_3.out", "2", "3", Map.class,
                widgetExpect2 + ", " + widgetExpect3, widgetForbidFrom1, BatchStatus.COMPLETED);
    }

    //2 unknown properties in json file will cause the read to fail
    @Test
    public void testUnknownJsonPropertyFail1_2() throws Exception {
        testReadWrite0(movieJsonUnknownProperty, "testUnknownJsonPropertyFail1_2.out", "1", "2", Movie.class,
                MovieTest.expect1_2, MovieTest.forbid1_2, BatchStatus.FAILED);
    }

    //configured 1 problem handler for unknow property 1, not for unknown property 2, so will still fail
    @Test
    public void testUnknownJsonPropertyFail2_4() throws Exception {
        this.deserializationProblemHandlers = "org.jberet.support.io.JsonItemReaderTest$UnknownHandler";
        testReadWrite0(movieJsonUnknownProperty, "testUnknownJsonPropertyFail2_4.out", "2", "4", Movie.class,
                MovieTest.expect2_4, MovieTest.forbid2_4, BatchStatus.FAILED);
        this.deserializationProblemHandlers = null;
    }

    //configured 2 problem handlers for both unknown properties, so the unknow properties are properly handled and the
    //job should complete.
    @Test
    public void testUnknownJsonProperty2_4() throws Exception {
        this.deserializationProblemHandlers = "org.jberet.support.io.JsonItemReaderTest$UnknownHandler, org.jberet.support.io.JsonItemReaderTest$Unknown2Handler";
        testReadWrite0(movieJsonUnknownProperty, "testUnknownJsonProperty2_4.out", "2", "4", Movie.class,
                MovieTest.expect2_4, MovieTest.forbid2_4, BatchStatus.COMPLETED);
        this.deserializationProblemHandlers = null;
    }

    private void testReadWrite0(final String resource, final String writeResource, final String start,
            final String end, final Class<?> beanType, final String expect, final String forbid,
            final BatchStatus jobStatus) throws Exception {
        final Properties params = CsvItemReaderWriterTest.createParams(CsvProperties.BEAN_TYPE_KEY,
                beanType.getName());
        params.setProperty(CsvProperties.RESOURCE_KEY, resource);

        final File writeResourceFile = new File(CsvItemReaderWriterTest.tmpdir, writeResource);
        params.setProperty("writeResource", writeResourceFile.getPath());

        if (start != null) {
            params.setProperty(CsvProperties.START_KEY, start);
        }
        if (end != null) {
            params.setProperty(CsvProperties.END_KEY, end);
        }
        if (jsonGeneratorFeatures != null) {
            params.setProperty("jsonGeneratorFeatures", jsonGeneratorFeatures);
        }
        if (deserializationProblemHandlers != null) {
            params.setProperty("deserializationProblemHandlers", deserializationProblemHandlers);
        }
        if (customDataTypeModules != null) {
            params.setProperty("customDataTypeModules", customDataTypeModules);
        }

        params.setProperty(CsvProperties.HEADER_KEY, MovieTest.header);
        CsvItemReaderWriterTest.setRandomWriteMode(params);

        final long jobExecutionId = jobOperator.start(jobName, params);
        final JobExecutionImpl jobExecution = (JobExecutionImpl) jobOperator.getJobExecution(jobExecutionId);
        jobExecution.awaitTermination(CsvItemReaderWriterTest.waitTimeoutMinutes, TimeUnit.MINUTES);
        Assert.assertEquals(jobStatus, jobExecution.getBatchStatus());

        if (jobStatus == BatchStatus.COMPLETED) {
            CsvItemReaderWriterTest.validate(writeResourceFile, expect, forbid);
        }
    }

    public static final class NoopInputDecorator extends InputDecorator {
        @Override
        public InputStream decorate(final IOContext ctxt, final InputStream in) throws IOException {
            System.out.printf("In decorate method of %s%n", this);
            return in;
        }

        @Override
        public InputStream decorate(final IOContext ctxt, final byte[] src, final int offset, final int length)
                throws IOException {
            System.out.printf("In decorate method of %s%n", this);
            return new ByteArrayInputStream(src, offset, length);
        }

        @Override
        public Reader decorate(final IOContext ctxt, final Reader src) throws IOException {
            System.out.printf("In decorate method of %s%n", this);
            return src;
        }
    }

    public static final class NoopOutputDecorator extends OutputDecorator {
        @Override
        public OutputStream decorate(final IOContext ctxt, final OutputStream out) throws IOException {
            System.out.printf("In decorate method of %s%n", this);
            return out;
        }

        @Override
        public Writer decorate(final IOContext ctxt, final Writer w) throws IOException {
            System.out.printf("In decorate method of %s%n", this);
            return w;
        }
    }

    public static final class JsonSerializer<Exception>
            extends com.fasterxml.jackson.databind.JsonSerializer<Exception> {
        @Override
        public void serialize(final Exception value, final JsonGenerator jgen, final SerializerProvider provider)
                throws IOException, JsonProcessingException {
            jgen.writeObject(value);
        }
    }

    public static final class JsonDeserializer<Exception>
            extends com.fasterxml.jackson.databind.JsonDeserializer<Exception> {
        @Override
        public Exception deserialize(final JsonParser jp, final DeserializationContext ctxt)
                throws IOException, JsonProcessingException {
            return jp.readValueAs(new TypeReference<Exception>() {
                @Override
                public Type getType() {
                    return super.getType();
                }

                @Override
                public int compareTo(final TypeReference<Exception> o) {
                    return super.compareTo(o);
                }
            });
        }
    }

    public static final class UnknownHandler extends DeserializationProblemHandler {
        @Override
        public boolean handleUnknownProperty(final DeserializationContext ctxt, final JsonParser jp,
                final com.fasterxml.jackson.databind.JsonDeserializer<?> deserializer, final Object beanOrClass,
                final String propertyName) throws IOException, JsonProcessingException {
            if (propertyName.equals("unknown")) {
                jp.skipChildren();
                return true;
            }
            return false;
        }
    }

    public static final class Unknown2Handler extends DeserializationProblemHandler {
        @Override
        public boolean handleUnknownProperty(final DeserializationContext ctxt, final JsonParser jp,
                final com.fasterxml.jackson.databind.JsonDeserializer<?> deserializer, final Object beanOrClass,
                final String propertyName) throws IOException, JsonProcessingException {
            if (propertyName.equals("unknown2")) {
                jp.skipChildren();
                return true;
            }
            return false;
        }
    }
}