Apart from the trick solution using reflection, you could also try jackson with one line as follows:
objectMapper.convertValue(o, Map.class);
A test case:
@Test
public void testConversion() {
User user = new User();
System.out.println(MapHelper.convertObject(user));
}
@Data
static class User {
String name = "Jack";
boolean male = true;
}
// output: you can have the right type normally
// {name=Jack, male=true}
Answer from Hearen on Stack OverflowApart from the trick solution using reflection, you could also try jackson with one line as follows:
objectMapper.convertValue(o, Map.class);
A test case:
@Test
public void testConversion() {
User user = new User();
System.out.println(MapHelper.convertObject(user));
}
@Data
static class User {
String name = "Jack";
boolean male = true;
}
// output: you can have the right type normally
// {name=Jack, male=true}
This is how you'd do it:
import java.util.Map;
import java.util.HashMap;
import java.util.Map.Entry;
import java.lang.reflect.Field;
public class Main {
public int a = 3;
public String b = "Hello";
public static void main(String[] args) {
Map<String, Object> map = parameters(new Main());
for (Entry<String, Object> entry : map.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}
}
public static Map<String, Object> parameters(Object obj) {
Map<String, Object> map = new HashMap<>();
for (Field field : obj.getClass().getDeclaredFields()) {
field.setAccessible(true);
try { map.put(field.getName(), field.get(obj)); } catch (Exception e) { }
}
return map;
}
}
Basically, you use reflection to get all of the fields in the class. Then, you access all of those fields of the object. Keep in mind that this only works for fields accessible from the method that gets the fields.
Well, you can achieve that with Jackson, too. (and it seems to be more comfortable since you were considering using jackson).
Use ObjectMapper's convertValue method:
final ObjectMapper mapper = new ObjectMapper(); // jackson's objectmapper
final MyPojo pojo = mapper.convertValue(map, MyPojo.class);
No need to convert into JSON string or something else; direct conversion does much faster.
A solution with Gson:
Gson gson = new Gson();
JsonElement jsonElement = gson.toJsonTree(map);
MyPojo pojo = gson.fromJson(jsonElement, MyPojo.class);
That's depends what the input is.
(Map<String, Object>) ois used for casting conversion, so the runtime type ofomust beMap, otherwiseClassCastExceptionwill be thrown:Object o = new HashMap<>(); Map<String, Object> map = (Map<String, Object>) o; // ok Object o = new ArrayList<>(); Map<String, Object> map = (Map<String, Object>) o; //ClassCastException Object o = new String(); Map<String, Object> map = (Map<String, Object>) o; //ClassCastExceptionObjectMapper().readValue(String content, JavaType valueType):Method to deserialize JSON content from given JSON content String.
which means the input should be a
Stringin valid json format. For example:Object input = "{\"key1\":{},\"key2\":{}}"; Map<String, Object> map = new ObjectMapper().readValue((String) input, new TypeReference<Map<String, Object>>() {}); System.out.println(map.size()); // 2
There is no "better". There are practical differences. But first, both options use type casting, and this raises the question "how are these two considered alternatives at all?"
Casting will only work if some object passes the instanceof Map test (first option), or if o passes the instanceof String test (second option).
In other words, the answer depends on the runtime class of some object.
So either this will fail with a class cast exception:
(Map<String, Object>) o;
Or this will fail with the same exception:
(String) o
Assuming the type checks will pass one way or the other, there are differences to be considered:
- If
some objectis compatible withMap<String, Object>, then casting should be preferred as it offers a performance advantage (consideringobjectMapper.convertValueas the alternative). In fact,readValueisn't even an option as the cast to string will fail. - If
some objectis a String, then you have no choice but to callreadValue, as you need to parse JSON.
As noted above, there's also objectMapper.convertValue, which in a smart way checks first instanceof before performing the conversion through JSON parsing. It's meant to convert objects from one type to another, if the two types have the same fields.