001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.juneau.marshall.parser; 018 019import static org.apache.juneau.commons.utils.IoUtils.*; 020import static org.apache.juneau.commons.utils.Shorts.*; 021import static org.apache.juneau.commons.utils.SystemUtils.*; 022 023import java.nio.charset.*; 024 025import org.apache.juneau.commons.collections.*; 026import org.apache.juneau.marshall.*; 027 028/** 029 * Subclass of {@link Parser} for character-based parsers. 030 * 031 * <h5 class='topic'>Description</h5> 032 * <p> 033 * This class is typically the parent class of all character-based parsers. 034 * It has 1 abstract method to implement on the session object... 035 * <ul> 036 * <li>{@link ParserSession#doRead(ParserPipe, ClassMeta)} 037 * </ul> 038 * 039 * <h5 class='section'>Notes:</h5><ul> 040 * <li class='note'>This class is thread safe and reusable. 041 * </ul> 042 * 043 * <h5 class='section'>See Also:</h5><ul> 044 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/SerializersAndParsers">Serializers and Parsers</a> 045 * </ul> 046 */ 047@SuppressWarnings({ 048 "java:S1192", // Duplicated literals (argument/property names) read more clearly inline than as constants 049 "java:S9149" // Per-format static factories intentionally shadow the parent's. 050}) 051public class ReaderParser extends Parser { 052 053 /** 054 * Builder class. 055 */ 056 @SuppressWarnings({ 057 "java:S119" // 'SELF' (CRTP self-type) is intentional and clearer than a single-letter name. 058 }) 059 public abstract static class Builder<SELF extends Builder<SELF>> extends Parser.Builder<SELF> { 060 061 private Charset streamCharset; 062 063 /** 064 * Constructor, default settings. 065 */ 066 protected Builder() { 067 streamCharset = env("ReaderParser.streamCharset", UTF8); 068 } 069 070 /** 071 * Copy constructor. 072 * 073 * @param copyFrom The builder to copy from. 074 * <br>Cannot be <jk>null</jk>. 075 */ 076 protected Builder(Builder<?> copyFrom) { 077 super(reqnn("copyFrom", copyFrom)); 078 streamCharset = copyFrom.streamCharset; 079 } 080 081 /** 082 * Copy constructor. 083 * 084 * @param copyFrom The bean to copy from. 085 * <br>Cannot be <jk>null</jk>. 086 */ 087 protected Builder(ReaderParser copyFrom) { 088 super(reqnn("copyFrom", copyFrom)); 089 streamCharset = copyFrom.streamCharset; 090 } 091 092 @Override /* Overridden from Context.Builder<?> */ 093 public ReaderParser build() { 094 return build(ReaderParser.class); 095 } 096 097 @Override /* Overridden from Context.Builder<?> */ 098 public abstract SELF copy(); 099 100 @Override /* Overridden from Context.Builder<?> */ 101 public HashKey hashKey() { 102 // @formatter:off 103 return HashKey.of( 104 super.hashKey(), 105 streamCharset 106 ); 107 // @formatter:on 108 } 109 110 /** 111 * Input stream charset. 112 * 113 * <p> 114 * The character set to use for converting <c>InputStreams</c> and byte arrays to readers. 115 * 116 * <p> 117 * Used when passing in input streams and byte arrays to {@link Parser#read(Object, Class)}. 118 * 119 * <h5 class='section'>Example:</h5> 120 * <p class='bjava'> 121 * <jc>// Create a parser that reads UTF-8 files.</jc> 122 * ReaderParser <jv>parser</jv> = JsonParser 123 * .<jsm>create</jsm>() 124 * .streamCharset(Charset.<jsm>forName</jsm>(<js>"UTF-8"</js>)) 125 * .build(); 126 * 127 * <jc>// Use it to read a UTF-8 encoded input stream.</jc> 128 * MyBean <jv>myBean</jv> = <jv>parser</jv>.read(<jk>new</jk> FileInputStream(<js>"MyBean.txt"</js>), MyBean.<jk>class</jk>); 129 * </p> 130 * 131 * @param value 132 * The new value for this property. 133 * <br>The default value is <js>"UTF-8"</js>. 134 * <br>Can be <jk>null</jk> (defaults to UTF-8). 135 * @return This object. 136 */ 137 public SELF streamCharset(Charset value) { 138 streamCharset = value; 139 return self(); 140 } 141 142 143 } 144 145 /** 146 * Concrete default builder leaf for the non-subclassed {@link ReaderParser#create()} / {@link ReaderParser#copy()} path. 147 */ 148 public static final class DefaultBuilder extends Builder<DefaultBuilder> { 149 150 DefaultBuilder() {} 151 152 DefaultBuilder(ReaderParser copyFrom) { 153 super(copyFrom); 154 } 155 156 DefaultBuilder(Builder<?> copyFrom) { 157 super(copyFrom); 158 } 159 160 @Override /* Overridden from Context.Builder<?> */ 161 public DefaultBuilder copy() { 162 return new DefaultBuilder(this); 163 } 164 } 165 166 /** 167 * Creates a new builder for this object. 168 * 169 * @return A new builder. 170 */ 171 @SuppressWarnings({ 172 "java:S1452" // Builder<?> wildcard return intentional; callers chain via fluent API without needing the concrete type 173 }) 174 public static Builder<?> create() { 175 return new DefaultBuilder(); 176 } 177 178 private final Charset streamCharset; 179 180 /** 181 * Constructor. 182 * 183 * @param builder The builder for this object. 184 * <br>Cannot be <jk>null</jk>. 185 */ 186 protected ReaderParser(Builder<?> builder) { 187 super(builder); 188 streamCharset = builder.streamCharset; 189 } 190 191 @Override /* Overridden from Context */ 192 public ReaderParserSession.Builder<?> createSession() { 193 return ReaderParserSession.create(this); 194 } 195 196 @Override /* Overridden from Context */ 197 public ReaderParserSession getSession() { return createSession().build(); } 198 199 @Override /* Overridden from Parser */ 200 public final boolean isReaderParser() { return true; } 201 202 /** 203 * Input stream charset. 204 * 205 * @see Builder#streamCharset(Charset) 206 * @return 207 * The character set to use for converting <c>InputStreams</c> and byte arrays to readers. 208 */ 209 protected final Charset getStreamCharset() { return streamCharset; } 210 211 @Override /* Overridden from Parser */ 212 protected FluentMap<String,Object> properties() { 213 return super.properties() 214 .a("streamCharset", streamCharset); 215 } 216}