001/* 002 * Copyright 2018-2020 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.batch.item.json; 018 019import org.apache.commons.logging.Log; 020import org.apache.commons.logging.LogFactory; 021 022import org.springframework.batch.item.ItemStreamReader; 023import org.springframework.batch.item.file.ResourceAwareItemReaderItemStream; 024import org.springframework.batch.item.support.AbstractItemCountingItemStreamItemReader; 025import org.springframework.core.io.Resource; 026import org.springframework.util.Assert; 027import org.springframework.util.ClassUtils; 028 029/** 030 * {@link ItemStreamReader} implementation that reads Json objects from a 031 * {@link Resource} having the following format: 032 * <p> 033 * <code> 034 * [ 035 * { 036 * // JSON object 037 * }, 038 * { 039 * // JSON object 040 * } 041 * ] 042 * </code> 043 * <p> 044 * 045 * The implementation is <b>not</b> thread-safe. 046 * 047 * @param <T> the type of json objects to read 048 * 049 * @author Mahmoud Ben Hassine 050 * @since 4.1 051 */ 052public class JsonItemReader<T> extends AbstractItemCountingItemStreamItemReader<T> implements 053 ResourceAwareItemReaderItemStream<T> { 054 055 private static final Log LOGGER = LogFactory.getLog(JsonItemReader.class); 056 057 private Resource resource; 058 059 private JsonObjectReader<T> jsonObjectReader; 060 061 private boolean strict = true; 062 063 /** 064 * Create a new {@link JsonItemReader} instance. 065 * @param resource the input json resource 066 * @param jsonObjectReader the json object reader to use 067 */ 068 public JsonItemReader(Resource resource, JsonObjectReader<T> jsonObjectReader) { 069 Assert.notNull(resource, "The resource must not be null."); 070 Assert.notNull(jsonObjectReader, "The json object reader must not be null."); 071 this.resource = resource; 072 this.jsonObjectReader = jsonObjectReader; 073 setExecutionContextName(ClassUtils.getShortName(JsonItemReader.class)); 074 } 075 076 /** 077 * Set the {@link JsonObjectReader} to use to read and map Json fragments to domain objects. 078 * @param jsonObjectReader the json object reader to use 079 */ 080 public void setJsonObjectReader(JsonObjectReader<T> jsonObjectReader) { 081 this.jsonObjectReader = jsonObjectReader; 082 } 083 084 /** 085 * In strict mode the reader will throw an exception on 086 * {@link #open(org.springframework.batch.item.ExecutionContext)} if the 087 * input resource does not exist. 088 * @param strict true by default 089 */ 090 public void setStrict(boolean strict) { 091 this.strict = strict; 092 } 093 094 @Override 095 public void setResource(Resource resource) { 096 this.resource = resource; 097 } 098 099 @Override 100 protected T doRead() throws Exception { 101 return jsonObjectReader.read(); 102 } 103 104 @Override 105 protected void doOpen() throws Exception { 106 if (!this.resource.exists()) { 107 if (this.strict) { 108 throw new IllegalStateException("Input resource must exist (reader is in 'strict' mode)"); 109 } 110 LOGGER.warn("Input resource does not exist " + this.resource.getDescription()); 111 return; 112 } 113 if (!this.resource.isReadable()) { 114 if (this.strict) { 115 throw new IllegalStateException("Input resource must be readable (reader is in 'strict' mode)"); 116 } 117 LOGGER.warn("Input resource is not readable " + this.resource.getDescription()); 118 return; 119 } 120 this.jsonObjectReader.open(this.resource); 121 } 122 123 @Override 124 protected void doClose() throws Exception { 125 this.jsonObjectReader.close(); 126 } 127 128}