001/* 002 * Copyright 2018 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 java.io.IOException; 020import java.io.InputStream; 021 022import com.fasterxml.jackson.core.JsonParser; 023import com.fasterxml.jackson.core.JsonToken; 024import com.fasterxml.jackson.databind.ObjectMapper; 025 026import org.springframework.batch.item.ParseException; 027import org.springframework.core.io.Resource; 028import org.springframework.util.Assert; 029 030/** 031 * Implementation of {@link JsonObjectReader} based on 032 * <a href="https://github.com/FasterXML/jackson">Jackson</a>. 033 * 034 * @param <T> type of the target object 035 * 036 * @author Mahmoud Ben Hassine 037 * @since 4.1 038 */ 039public class JacksonJsonObjectReader<T> implements JsonObjectReader<T> { 040 041 private Class<? extends T> itemType; 042 043 private JsonParser jsonParser; 044 045 private ObjectMapper mapper = new ObjectMapper(); 046 047 private InputStream inputStream; 048 049 /** 050 * Create a new {@link JacksonJsonObjectReader} instance. 051 * @param itemType the target item type 052 */ 053 public JacksonJsonObjectReader(Class<? extends T> itemType) { 054 this.itemType = itemType; 055 } 056 057 /** 058 * Set the object mapper to use to map Json objects to domain objects. 059 * @param mapper the object mapper to use 060 */ 061 public void setMapper(ObjectMapper mapper) { 062 Assert.notNull(mapper, "The mapper must not be null"); 063 this.mapper = mapper; 064 } 065 066 @Override 067 public void open(Resource resource) throws Exception { 068 Assert.notNull(resource, "The resource must not be null"); 069 this.inputStream = resource.getInputStream(); 070 this.jsonParser = this.mapper.getFactory().createParser(this.inputStream); 071 Assert.state(this.jsonParser.nextToken() == JsonToken.START_ARRAY, 072 "The Json input stream must start with an array of Json objects"); 073 } 074 075 @Override 076 public T read() throws Exception { 077 try { 078 if (this.jsonParser.nextToken() == JsonToken.START_OBJECT) { 079 return this.mapper.readValue(this.jsonParser, this.itemType); 080 } 081 } catch (IOException e) { 082 throw new ParseException("Unable to read next JSON object", e); 083 } 084 return null; 085 } 086 087 @Override 088 public void close() throws Exception { 089 this.inputStream.close(); 090 this.jsonParser.close(); 091 } 092 093}