Здесь мои 2 цента.
Или вы можете использовать простой метод с дженериками. Кусок торта.
public static <K,V> Map<V, K> invertMap(Map<K, V> toInvert) {
Map<V, K> result = new HashMap<V, K>();
for(K k: toInvert.keySet()){
result.put(toInvert.get(k), k);
}
return result;
}
Конечно, у вас должна быть карта с уникальными значениями. В противном случае один из них будет заменен.
У меня была ситуация, когда я использовал настраиваемый десериализатор, но я хотел, чтобы стандартный десериализатор выполнял большую часть работы, а затем, используя SAME json, выполнял некоторые дополнительные настраиваемые действия. Однако после того, как десериализатор по умолчанию выполнил свою работу, текущее местоположение объекта JsonParser вышло за рамки необходимого мне текста json. Поэтому у меня возникла та же проблема, что и у вас: как получить доступ к базовой строке json.
Вы можете использовать JsonParser.getCurrentLocation.getSourceRef()
, чтобы получить доступ к исходному источнику json. Используйте JsonParser.getCurrentLocation().getCharOffset()
, чтобы найти текущее местоположение в источнике json.
Вот решение, которое я использовал:
public class WalkStepDeserializer extends StdDeserializer<WalkStep> implements
ResolvableDeserializer {
// constructor, logger, and ResolvableDeserializer methods not shown
@Override
public MyObj deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException,
JsonProcessingException {
MyObj myObj = null;
JsonLocation startLocation = jp.getCurrentLocation();
long charOffsetStart = startLocation.getCharOffset();
try {
myObj = (MyObj) defaultDeserializer.deserialize(jp, ctxt);
} catch (UnrecognizedPropertyException e) {
logger.info(e.getMessage());
}
JsonLocation endLocation = jp.getCurrentLocation();
long charOffsetEnd = endLocation.getCharOffset();
String jsonSubString = endLocation.getSourceRef().toString().substring((int)charOffsetStart - 1, (int)charOffsetEnd);
logger.info(strWalkStep);
// Special logic - use JsonLocation.getSourceRef() to get and use the entire Json
// string for further processing
return myObj;
}
}
И информация об использовании десериализатора по умолчанию в пользовательском десериализаторе находится в . Как мне вызвать десериализатор по умолчанию из пользовательского десериализатора в Джексоне
5 лет спустя, но это было мое решение:
Я преобразовал jsonParser в строку
String requestString = jsonParser.readValueAsTree().toString();
Затем я преобразовал эту строку в JsonParser
JsonFactory factory = new JsonFactory();
JsonParser parser = factory.createParser(requestString);
Затем я перебрал свой синтаксический анализатор
ObjectMapper objectMapper = new ObjectMapper();
while(!parser.isClosed()){
JsonToken jsonToken = parser.nextToken();
if(JsonToken.FIELD_NAME.equals(jsonToken)){
String currentName = parser.getCurrentName();
parser.nextToken();
switch (currentName) {
case "someObject":
Object someObject = objectMapper.readValue(parser, Object.class)
//validate someObject
break;
}
}
Мне нужно было сохранить исходную строку json для целей регистрации, поэтому я сделал это в первую очередь. Была головная боль, чтобы узнать, но наконец сделал это, и я надеюсь, что помогу кому-то :))
То, что вы пытаетесь сделать, выходит за рамки сферы деятельности Джексона (и большинства, если не всех других библиотек Java JSON). Что вы хотите сделать, так это полностью использовать входной поток в строку, а затем попытаться преобразовать эту строку в объект JSON с помощью Jackson. Если преобразование завершится неудачно, сделайте что-нибудь с промежуточной строкой, иначе продолжайте в обычном режиме. Вот пример, который для удобства использует превосходную библиотеку Apache Commons IO :
final InputStream stream ; // Your stream here
final String json = IOUtils.toString(stream);
try {
final JsonNode node = new ObjectMapper().readTree(json);
// Do something with JSON object here
} catch(final JsonProcessingException jpe) {
// Do something with intermediate string here
}
Создание собственного десериализатора, в котором я хотел десериализовать определенное поле в виде текста i.s.o. правильное DTO, это решение, которое я придумал.
Я написал свой собственный JsonToStringDeserializer следующим образом:
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.TreeNode;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import lombok.NoArgsConstructor;
import org.apache.commons.lang3.StringEscapeUtils;
import java.io.IOException;
/**
* Deserialiser to deserialise any Json content to a String.
*/
@NoArgsConstructor
public class JsonToStringDeserializer extends JsonDeserializer<String> {
/**
* Deserialise a Json attribute that is a fully fledged Json object, into a {@link String}.
* @param jsonParser Parsed used for reading JSON content
* @param context Context that can be used to access information about this deserialization activity.
* @return The deserialized value as a {@link String}.
* @throws IOException
*/
@Override
public String deserialize(JsonParser jsonParser, DeserializationContext context) throws IOException {
final TreeNode node = jsonParser.getCodec().readTree(jsonParser);
final String unescapedString = StringEscapeUtils.unescapeJava(node.toString());
return unescapedString.substring(1, unescapedString.length()-1);
}
}
Аннотируйте поле, которое вы хотите десериализовать, следующим образом:
@JsonDeserialize(using = JsonToStringDeserializer.class)
Сначала я следовал совету, который сказал использовать TreeNode как this:
final TreeNode treeNode = jsonParser.getCodec().readTree(jsonParser);
return treeNode.toString();
Но тогда вы получите строку Json, которая содержит escape-символы.