I have a json string and my requirement is to covert into map, where key will be field of the json. below is my json
{
"A":[
{
"B":[
{
"C":[
{
"D1":"V1",
"D2":"X1",
"D3":Y1,
"D4":"Z1"
},
{
"D1":"V2",
"D2":"X2",
"D3":Y2,
"D4":"Z2"
}
]
}
]
}
]
}
Key should look like "A->B->C->D1" and corresponding value V1,V2.
Map signature should look like Map<String,List<String>>. Similar kind of question posted here but my problem is to create key out of json field.Let me know if more information is required. Thanks in advance.
I did something that answers the exact structure of yours where i changed the value of D3 to be also string:
class Wraper that is the whole object
public class Wraper {
public Wraper() {}
#JsonProperty("A") A[] a;
}
class A
public class A {
#JsonProperty("B") B[] b;
}
Class B
public class B {
#JsonProperty("C") C[] c;
}
Class C
public class C {
#JsonProperty("D1") String d1;
#JsonProperty("D2") String d2;
#JsonProperty("D3") String d3;
#JsonProperty("D4") String d4;
}
And finally where I tested:
static final String JSON_VAL="{\"A\":[{\"B\":[{\"C\":[{\"D1\":\"V1\",\"D2\":\"X1\",\"D3\":\"Y1\",\"D4\":\"Z1\"},{\"D1\":\"V2\",\"D2\":\"X2\",\"D3\":\"Y2\",\"D4\":\"Z2\"}]}]}]}";
final ObjectMapper mapper = new ObjectMapper();
final Wraper wraper = mapper.readValue(JSON_VAL, Wraper.class);
final Map<String,List<String>> map = new HashMap<>();
Arrays.stream(wraper.a).forEach(a -> {
Arrays.stream(a.b).forEach(b -> {
final List<String> d1 = new ArrayList<>();
final List<String> d2 = new ArrayList<>();
final List<String> d3 = new ArrayList<>();
final List<String> d4 = new ArrayList<>();
Arrays.stream(b.c).forEach(c -> {
d1.add(c.d1);
d2.add(c.d2);
d3.add(c.d3);
d4.add(c.d4);
});
map.put("A->B->C->D1", d1);
map.put("A->B->C->D2", d2);
map.put("A->B->C->D3", d3);
map.put("A->B->C->D4", d4);
});
});
Try Jackson using the correct Java class definitions (based on the JSON).
Here is some code:
public class topElement
{
private ElementA[] A;
public ElementA[] getA()
{
return A;
}
public void setA(
final ElementA[] newValue)
{
A = newValue;
}
}
public class ElementA
{
private ElementB[] B;
public ElementB[] getB()
{
return B;
}
public void setB(
final ElementB[] newValue)
{
B = newValue;
}
}
public class ElementB
{
private ElementC[] C;
public ElementC[] getC()
{
return C;
}
public void setC(
final ElementC[] newValue)
{
C = newValue;
}
}
public class ElementC
{
private Map blammyMap;
public Map getBlammyMap()
{
return blammyMap;
}
public void setBlammyMap(
final Map newValue)
{
blammyMap = newValue;
}
}
}
Related
Looking for a best solution for the object recursion problem. Below is the example:
Class:
public class SomeObject {
private List<SomeObject> objects;
}
Data:
Input:
SomeObject has List of objects and every Object in list is of SomeObject Type and has list inside them. (Recursive in nature)
Requirement is to flatten them and put them in a single arraylist.
The flatten List should have all the SomeObject types.
Can anyone suggest what's the best way to handle this case. Thanks!
If you are not using Java 8, You might consider doing it this way.
import java.util.ArrayList;
import java.util.List;
public class TestClass {
static List<SomeObject> flatList = new ArrayList<SomeObject>();
public static void flatten(SomeObject object) {
if (object != null ){
if( object.getObjects() != null && !object.getObjects().isEmpty()) {
for (SomeObject o : object.getObjects()) {
flatten(o);
flatList.add(object);
}
}
}
}
public static void main(String[] args) {
SomeObject o1 = new SomeObject("1");
SomeObject o2 = new SomeObject("2");
SomeObject o3 = new SomeObject("3");
SomeObject o4 = new SomeObject("4");
o1.addObject(o2);
o2.addObject(o3);
o3.addObject(o4);
flatten(o1);
for (SomeObject obj : flatList){
System.out.println(obj.getObjectName());
}
}
}
class SomeObject {
String objectName = "";
public SomeObject(String name) {
this.objectName = name;
}
private List<SomeObject> objects = new ArrayList<SomeObject>();
public List<SomeObject> getObjects() {
return objects;
}
public void setObjects(List<SomeObject> objects) {
this.objects = objects;
}
public void addObject(SomeObject o){
objects.add(o);
}
public String getObjectName() {
return objectName;
}
}
To make recursion, the method for a given object would require to :
add itself : add to list
ask its children to do same : collect all children getAllChildren()
public class Foo {
private String s;
private List<Foo> fooList = new ArrayList<>();
public Foo(String a) {
s = a;
}
public static void main(String[] args) {
Foo a = new Foo("a");
Foo b = new Foo("b");
Foo c = new Foo("c");
Foo d = new Foo("d");
Foo e = new Foo("e");
a.fooList.add(b);
b.fooList.add(c);
c.fooList.add(e);
a.fooList.add(d);
List<Foo> list = a.getAllChildren();
System.out.println(list);
}
private List<Foo> getAllChildren() {
List<Foo> l = fooList.stream().flatMap(elt -> elt.getAllChildren().stream())
.collect(Collectors.toList());
l.add(this);
return l;
}
#Override
public String toString() { return s; }
}
Input Structure :
a-b-c-d
\ \
e f
Output List :
[d, f, c, b, e, a]
Im trying to get the id of a posto from an hashmap to compare the value in another class:
My class Posto:
public class Posto {
private int id;
private Point posicao;
private int capacidade;
private int quantidadeAtual;
private int gastoMedio;
public Posto(int id, Point posicao, int capacidade, int quantidadeAtual, int gastoMedio) {
this.id = id;
this.posicao = posicao;
this.capacidade = capacidade;
this.quantidadeAtual = quantidadeAtual;
this.gastoMedio = gastoMedio;
}
public int getPostoId() {
return id;
}
public void setPostoId(int id) {
this.id = id;
}
public Point getPostoPosicao() {
return posicao;
}
public void setPostoPosicao(Point posicao) {
this.posicao = posicao;
}
public int getPostoCapacidade() {
return capacidade;
}
public void setPostoCapacidade(int capacidade) {
this.capacidade = capacidade;
}
public int getPostoQuantidadeAtual() {
return quantidadeAtual;
}
public void setPostoQuantidadeAtual(int quantidadeAtual) {
this.quantidadeAtual = quantidadeAtual;
}
public int getPostoGastoMedio() {
return gastoMedio;
}
public void setPostoGastoMedio(int gastoMedio) {
this.gastoMedio = gastoMedio;
}
My MAIN class where i fill the hashmaps like this:
public class Main {
public static void main(String[] args) {
Central c = new Central( new Point(20, 300) );
setupCentral( c );
MenuCentral mc = new MenuCentral( c );
mc.menuPrincipal();
}
private static void setupCentral(Central c) {
//Posto p1 = new Posto(1,new Point(2,3),24,40,30);
c.addPosto(new Posto(1,new Point(10,10),10,200,180));
c.addPosto(new Posto(2,new Point(700,15),15,300,200));
}
}
And now my CENTRAL class where i have the method "addPosto" to fill the hashmap and i need the method "getPosto" to get the ids to compare in other class but i can't do it, i'm a little bit confused about the hashmaps.
public class Central {
private Point posicao;
private Map<Integer, Object> camioes = new HashMap<Integer,Object>( );
private Map<Integer,Object> postos = new HashMap<Integer,Object>( );
public Central(Point posicao) {
this.posicao = posicao;
}
public Point getPosicao() {
return posicao;
}
public void setPosicao(Point posicao) {
this.posicao = posicao;
}
public void addPosto( Posto p ){
postos.put(p.getPostoId(), p);
}
***public int getPosto (int id){
}***
}
Your Map has only one value type.
private final Map<Integer, Posto> postos = new HashMap<>();
And you only add this type.
public void addPosto( Posto p ){
postos.put(p.getPostoId(), p);
}
so it makes sense to expect this type.
public Posto getPosto(int id) {
return postos.get(id);
}
If you want to leave the Map as it is (which is a bad idea IMHO you can use an explicit cast)
public Posto getPosto(int id) {
return (Posto) postos.get(id);
}
This is needlessly verbose and error prone. At some point doing this will almost certainly lead to a bug which never needed to happen.
public Posto getPosto (int id)
{
return postos.get(id);
}
sice you are adding posto class to the hashmap use generics
private Map<Integer, Posto> camioes = new HashMap<Integer,Posto>( );
private Map<Integer,Posto> postos = new HashMap<Integer,Posto>( );
you can iterate the hashmap and get all the values
for (Integer key : camioes.keySet()) {
Posto p = postos.get(key);
System.out.println(p.getPostoId());
}
}
I have a SourceClass with following parameters as:
class SourceClass{
public Integer a;
public Integer b;
}
And a DestinationClass as:
class DestinationClass {
public Integer a;
public Integer b;
}
And here is my test code:
public static void main(String[] args) {
Mapper mapper = new DozerBeanMapper();
SourceClass src= new SourceClass();
src.a= 1;
src.b= 2;
DestinationClass dest = mapper.map(src, DestinationClass.class);
System.out.println(dest.a + " " + dest.b);
}
The last line of the code is showing as null null, now I have tried by giving the getter/setter as well but didn't worked, I finally got the output by specifying #Mapping annotation giving the name of the variable to map like #Mappinf("a"), but as you see my variable names are same, can't dozermapper do it by itself?Because here it is written that it maps the same named variables automatically.
Ok so first of all either change SourceClass variables to Strings or change src.a and src.b values to be Integers.
Secondly you need to have getters and setters in both SourceClass and DestinationClass because dozer relies on them regardless if the variables are public or private.
The following solution works:
public class SourceClass{
private Integer a;
private Integer b;
public Integer getA(){
return a;
}
public void setA(Integer a){
this.a = a;
}
public Integer getB()
{
return b;
}
public void setB(Integer b){
this.b = b;
}
}
public class DestClass{
private Integer a;
private Integer b;
public Integer getA(){
return a;
}
public void setA(Integer a){
this.a = a;
}
public Integer getB(){
return b;
}
public void setB(Integer b){
this.b = b;
}
}
public static void main(String[] args)
{
Mapper mapper = new DozerBeanMapper();
SourceClass src = new SourceClass();
src.setA(1);
src.setB(2);
DestClass dest = mapper.map(src, DestClass.class);
System.out.println(dest.getA() + " " + dest.getB());
}
I hope this helps.
public class ObjectToProxy
{
List<ObjectToProxy> potentiallyCircularReference;
}
public class SubClass
{
private ObjectToProxy aField;
Set<ObjectToProxy> aSetOfObjectsToProxy;
}
public class CrazyObject
{
Map<Integer, ObjectToProxy> proxiedObjects;
List<SubClass> manySubClasses;
}
public class ComplexObject
{
List<CrazyObject> crazyObjects;
private final ObjectToProxy storedAsAField;
}
I have a complex object graph. Lets say it looks a little like the one above (even though it is much deeper in the real system). I would like, after being given ComplexObject, to be able to traverse the object graph and replace all ObjectToProxys with a proxying object.
Is this doable?
The reason for this is that we have some pretty big nasty objects which we partially load on the servers side (legacy, you're my friend!). We have a semi-working solution that uses proxying on the client side to go through and loads the full object when needed.
edit I would like to replace every instance of ObjectProxy connected to a ComplexObject.
public static class ProxyObject extends ObjectToProxy
{
private final ObjectToProxy objectToProxy;
public ProxyObject(ObjectToProxy objectToProxy)
{
this.objectToProxy = objectToProxy;
}
#Override
public String toString()
{
return "ProxyObject";
}
}
public static class ObjectToProxy
{
List<ObjectToProxy> potentiallyCircularReference;
public ObjectToProxy()
{
potentiallyCircularReference = new ArrayList<>();
potentiallyCircularReference.add(this);
}
#Override
public String toString()
{
return "ObjectToProxy";
}
}
public static class SubClass
{
ObjectToProxy aField;
Set<ObjectToProxy> aSetOfObjectsToProxy;
}
public static class CrazyObject
{
Map<Integer, ObjectToProxy> proxiedObjects;
List<SubClass> manySubClasses;
public CrazyObject()
{
proxiedObjects = new HashMap<>();
proxiedObjects.put(1, new ObjectToProxy());
}
}
public static class ComplexObject
{
List<CrazyObject> crazyObjects;
final ObjectToProxy storedAsAField;
public ComplexObject()
{
this.storedAsAField = new ObjectToProxy();
crazyObjects = new ArrayList<>();
crazyObjects.add(new CrazyObject());
}
#Override
public String toString()
{
return "myField: " + storedAsAField.toString();
}
}
public static void main(String[] args) throws Exception
{
ComplexObject obj = new ComplexObject();
Set<Object> visitedObjects = Sets.newIdentityHashSet();
Queue<Object> objectsToVisit = new LinkedList<>();
visitedObjects.add(obj);
objectsToVisit.add(obj);
while (!objectsToVisit.isEmpty())
{
handleFields(objectsToVisit.poll(), visitedObjects, objectsToVisit);
}
System.out.println(obj.toString());
}
private static void handleFields(Object obj, Set<Object> visitedObjects, Queue<Object> objectsToVisit) throws Exception
{
List<Field> fields = getAllFields(obj);
for (Field field : fields)
{
field.setAccessible(true);
Object fieldValue = field.get(obj);
if (fieldValue != null && !visitedObjects.contains(fieldValue))
{
if (fieldValue instanceof Object[])
{
visitedObjects.add(fieldValue);
Object[] array = (Object[])fieldValue;
for (Object arrayObj : array)
{
if (arrayObj != null && !objectsToVisit.contains(arrayObj))
{
visitedObjects.add(arrayObj);
if (!DontLookAt.contains(arrayObj.getClass()))
objectsToVisit.add(arrayObj);
}
}
}
else
{
if (!DontLookAt.contains(fieldValue.getClass()))
objectsToVisit.add(fieldValue);
}
if (fieldValue.getClass().equals(ObjectToProxy.class))
{
field.set(obj, new ProxyObject((ObjectToProxy)fieldValue));
}
else if (fieldValue instanceof ObjectToProxy[])
{
ObjectToProxy[] array = (ObjectToProxy[])fieldValue;
for (int i = 0; i < array.length; i++)
{
if (array[i] != null)
array[i] = new ProxyObject(array[i]);
}
}
}
}
}
private static final Set<Class> DontLookAt = getDontLookAtSet();
private static Set<Class> getDontLookAtSet()
{
Set<Class> set = new HashSet<>();
set.add(Long.class);
set.add(Boolean.class);
set.add(Integer.class);
set.add(String.class);
set.add(Byte.class);
set.add(Double.class);
set.add(Float.class);
set.add(Class.class);
return set;
}
private static List<Field> getAllFields(Object obj) throws Exception
{
List<Field> output = new ArrayList<>();
Class klazz = obj.getClass();
while (!klazz.equals(Object.class))
{
Field[] fields = klazz.getDeclaredFields();
output.addAll(Arrays.asList(fields));
klazz = klazz.getSuperclass();
}
return output;
}
For anyone wondering, The above simulates and does what I'm after. I'm sure it isn't perfect, but it is good enough for my purposes.
I wondered how I could change ordering-direction only on some contitional. In my case Strings starting with 'BB' should be ordered in the other direction, everything else should be ordered as usual.
My Test-Class:
public class StringTest {
public static void main(String[] args) {
SomeClass someClass1= new SomeClass("AA");
SomeClass someClass2= new SomeClass("AB");
SomeClass someClass3= new SomeClass("CB4");
SomeClass someClass4= new SomeClass("BB7");
SomeClass someClass5= new SomeClass("BB9");
SomeClass someClass6= new SomeClass("BB3");
SomeClass someClass7= new SomeClass("CB3");
List<SomeClass> list = new ArrayList<SomeClass>();
list.add(someClass1);
list.add(someClass2);
list.add(someClass3);
list.add(someClass4);
list.add(someClass5);
list.add(someClass6);
list.add(someClass7);
Collections.sort(list);
for (SomeClass someClass : list) {
System.out.println(someClass.getSomeField());
}
}
}
My Comparator:
public class SomeClass implements Comparable<SomeClass>
{
private String someField;
public int compareTo(final SomeClass o)
{
int res = 0;
if (someField.startsWith("BB"))
{
res = o.someField.compareTo(someField);
}
else
{
res = someField.compareTo(o.someField);
}
return res;
}
}
My desired output:
AA
AB
BB9
BB7
BB3
CB3
CB4
The actual result so far:
AA
AB
CB3
BB9
BB7
BB3
CB4
Jonny
You need to make sure your Comparator applies the different sorting only when both elements start with "BB". Right now your Comparator applies the different sorting even if you compare "BB9" with "CB3" and therefore the latter is being sorted in front of BB9.
public class SomeClass implements Comparable<SomeClass>
{
private String someField;
public int compareTo(final SomeClass o)
{
int res = 0;
if (someField.startsWith("BB") && o.someField.startsWith("BB"))
{
res = o.someField.compareTo(someField);
}
else
{
res = someField.compareTo(o.someField);
}
return res;
}
}
if(someField.startsWith("BB") && o.someField.startsWith("BB")))
Try this change in your compareTo method which may solve your problem.