我有一个Java类:
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class Filescan {
public static void main(String[] args) throws IOException {
Filescan sc = new Filescan();
sc.findWords("src/main/resources/files", new String[]{"author", "book"}, true);
}
// kind of Tuple/Map.Entry
static class Pair<K,V>{
final K key;
final V value;
Pair(K key, V value){
this.key = key;
this.value = value;
}
@Override
public String toString() {
return key + " " + value;
}
}
public void findWords(String directory, String[] words, boolean ignorecase) throws IOException{
final String[] searchWords = ignorecase ? toLower(words) : words;
try (Stream<Path> stream = Files.walk(Paths.get(directory)).filter(Files::isRegularFile)) {
long startTime = System.nanoTime();
List<Pair<Path,Map<String, List<Integer>>>> result = stream
// you can test it with parallel execution, maybe it is faster
.parallel()
// searching
.map(path -> findWordsInFile(path, searchWords, ignorecase))
// filtering out empty optionals
.filter(Optional::isPresent)
// unwrap optionals
.map(Optional::get).collect(Collectors.toList());
System.out.println("Time taken = " + TimeUnit.NANOSECONDS.toSeconds(System.nanoTime()
- startTime) + " seconds");
System.out.println("result:");
result.forEach(System.out::println);
}
}
private String[] toLower(String[] words) {
String[] ret = new String[words.length];
for (int i = 0; i < words.length; i++) {
ret[i] = words[i].toLowerCase();
}
return ret;
}
private static Optional<Pair<Path,Map<String, List<Integer>>>> findWordsInFile(Path path, String[] words, boolean ignorecase) {
try (BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(path.toFile())))) {
String line = br.readLine();
line = ignorecase & line != null ? line.toLowerCase() : line;
Map<String, List<Integer>> map = new HashMap<>();
int linecount = 0;
while(line != null){
for (String word : words) {
if(line.contains(word)){
if(!map.containsKey(word)){
map.put(word, new ArrayList<Integer>());
}
map.get(word).add(linecount);
}
}
line = br.readLine();
line = ignorecase & line != null ? line.toLowerCase() : line;
linecount++;
}
if(map.isEmpty()){
// returning empty optional when nothing in the map
return Optional.empty();
}else{
// returning a path-map pair with the words and the rows where each word has been found
return Optional.of(new Pair<Path,Map<String, List<Integer>>>(path, map));
}
} catch (IOException ex) {
throw new UncheckedIOException(ex);
}
}
}
我已经使用Gson将一些Object1实例保存为JSON字符串:
public class Object1 {
private int field1;
private String field2;
private Object2 object2;
private boolean field3;
}
然后我向Object1类添加了新的String字段:
String jsonString = new Gson().toJson(object1, Object1.class);
现在我无法使用方法将json字符串反序列化为Object1实例:
public class Object1 {
private int field1;
private String field2;
private String field4;
private Object2 object2;
private boolean field3;
}
由于Gson引发异常:
System.err:com.google.gson.JsonSyntaxException:java.lang.IllegalStateException:预期为字符串,但在第1行444列$ .c处为BEGIN_OBJECT 在com.google.gson.internal.bind.ReflectiveTypeAdapterFactory $ Adapter.read(ReflectiveTypeAdapterFactory.java:224) 在com.google.gson.Gson.fromJson(Gson.java:887) 在com.google.gson.Gson.fromJson(Gson.java:852) 在com.google.gson.Gson.fromJson(Gson.java:801) 在com.google.gson.Gson.fromJson(Gson.java:773)
但是为什么呢?我有没有一个字段的JSON字符串,这不是问题。为什么我不能反序列化?
答案 0 :(得分:0)
Expected a string but was BEGIN_OBJECT
field4
中的json字符串不是String类型,请使用Json to POJO生成器来创建适当的对象。
答案 1 :(得分:0)
@ user523392说:
成员变量必须与JSON响应中给出的完全匹配
不是这种情况。
有一些选项可用于指定Java字段名称如何映射到JSON元素名称。
一种适用于上述原始问题的解决方案是用@SerializedName注释Java类成员,以非常明确地声明其映射到的JSON元素名称。
// output: [MyObject: element=value1, elementTwo=value2]
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.annotations.SerializedName;
public class Foo
{
static String jsonInput =
"{" +
"\"element\":\"value1\"," +
"\"@element-two\":\"value2\"" +
"}";
public static void main(String[] args)
{
GsonBuilder gsonBuilder = new GsonBuilder();
Gson gson = gsonBuilder.create();
MyObject object = gson.fromJson(jsonInput, MyObject.class);
System.out.println(object);
}
}
class MyObject
{
String element;
@SerializedName("@element-two")
String elementTwo;
@Override
public String toString()
{
return String.format(
"[MyObject: element=%s, elementTwo=%s]",
element, elementTwo);
}
}
另一种方法是创建一个自定义FieldNamingStrategy,以指定如何将Java成员名称转换为JSON元素名称。本示例将相同的名称映射应用于所有Java成员名称。这种方法不适用于上面的原始示例,因为并非所有JSON元素名称都遵循相同的命名模式-它们并非都以'@'开头,并且有些使用驼峰式命名而不是使用'-来分隔名称部分'。构建Gson实例(gsonBuilder.setFieldNamingStrategy(new MyFieldNamingStrategy());)时,将使用此FieldNamingStrategy的实例。
class MyFieldNamingStrategy implements FieldNamingStrategy
{
// Translates the field name into its JSON field name representation.
@Override
public String translateName(Field field)
{
String name = field.getName();
StringBuilder translation = new StringBuilder();
translation.append('@');
for (int i = 0, length = name.length(); i < length; i++)
{
char c = name.charAt(i);
if (Character.isUpperCase(c))
{
translation.append('-');
c = Character.toLowerCase(c);
}
translation.append(c);
}
return translation.toString();
}
}
管理Java字段名称如何映射到JSON元素名称的另一种方法是在构建Gson实例时指定FieldNamingPolicy,例如gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_DASHES);。但是,这也不适用于原始示例,因为它对所有情况都应用了相同的名称映射策略。
答案 2 :(得分:0)
事实证明,问题出在混淆之中。
如果您不使用@SerializedName注释结果,则JSON可能如下所示:
{“ a”:3436213,“ b”:“某些字符串”,“ c”:{.............},“ d”:true}
我们没有使用它,因为它不是DTO。在这种情况下,我们仅使用JSON来存储一些不重要的内部数据。但这对我来说是非常有趣的一课。