Tengo un conjunto único de localización de objetos con datos como
location 1: "USA", "AZ", "Phoenix"
location 2: "USA", "AZ", "Scottsdale"
location 3: "USA", "AZ", "Peoria"
Front end needs following json structure to render UI:
"USA"-> [{"AZ" -> ["Phoenix", "Scottsdale","Peoria"]},
{"MD" -> ["Baltimore", "Gaithersburg","OwingsMills"]}
]
Java POJO para Location.java
He escrito código que está montón de líneas para recorrer conjunto de posiciones y construir objetos que contienen País Conjunto de objetos que contienen Estado Conjunto de City objetos usando el objeto FacetsGeo y generar JSON fuera de este modelos de datos.
Me refiero, podría haber una mejor manera de hacer esto: probablemente con Java API 8 Streaming.
Cualquier ayuda apreciado, como he dicho anteriormente es de datos de ejemplo, cómo Ubicaciones plana construida.
public class Location {
private final String country;
private final String state;
private final String city;
public Location(final String country, final String state, final
String city) {
this.country = country;
this.state = state;
this.city = city;
}
public String getCountry() {
return country;
}
public String getState() {
return state;
}
public String getCity() {
return city;
}
@Override
public boolean equals(Object thatLocation) {
if (thatLocation == this) return true;
if (!(thatLocationCriteria instanceof Location)) {
return false;
}
Location location = (Location) thatLocation;
return Objects.equals(this.country, location.country) &&
Objects.equals(this.state, location.state) &&
Objects.equals(this.city, location.city);
}
@Override
public int hashCode() {
return Objects.hash(this.country, this.state, this.city);
}
}
FacetsGeo.java
public class FacetsGeo {
private String label;
private String value;
private String type;
private String subtype;
private List<FacetsGeo> childFacetsGeo;
}
Lo que intenté generar por encima de la estructura de datos front-end:
` List<FacetsGeo> facetsList = new ArrayList<FacetsGeo>();
Optional<locations> locationsOptional = Optional.ofNullable(locations);
if(locationsOptional.isPresent()) {
//locations
for (final Location location : locationsOptional.get().getLocations()) {
FacetsGeo facetCountry = new FacetsGeo();
if(location.getCountry() != null
&& location.getCountry().equalsIgnoreCase("United States")
&& location.getState() != null) {
boolean countryExists = false;
for(FacetsGeo facetGeo: facetsList) {
if(facetGeo.getType() != null && facetGeo.getSubtype() != null
&& facetGeo.getType().equalsIgnoreCase("location")
&& facetGeo.getSubtype().equalsIgnoreCase("country")
&& facetGeo.getValue().equalsIgnoreCase(location.getCountry())) {
facetCountry = facetGeo;
if(facetCountry.getSubCriteria() == null) {
facetCountry.setSubCriteria(new ArrayList<FacetsGeo>());
}
countryExists = true;
break;
}
}
if(!countryExists) {
facetCountry.setLabel(location.getCountry());
facetCountry.setValue(location.getCountry());
facetCountry.setType("location");
facetCountry.setSubtype("country");
FacetsGeo subcriteriaState = new FacetsGeo();
subcriteriaState.setLabel(location.getState());
subcriteriaState.setValue(location.getState());
subcriteriaState.setType("location");
subcriteriaState.setSubtype("state");
FacetsGeo subcriteria = new FacetsGeo();
subcriteria.setLabel(location.getCity());
subcriteria.setValue(location.getCity());
subcriteria.setType("location");
subcriteria.setSubtype("city");
subcriteriaState.setSubCriteria(new ArrayList<FacetsGeo>());
subcriteriaState.getSubCriteria().add(subcriteria);
facetCountry.setSubCriteria(new ArrayList<FacetsGeo>());
facetCountry.getSubCriteria().add(subcriteriaState);
searchBarFacetsList.add(searchBarFacetCountry);
} else {
FacetsGeo subcriteriaCity = new FacetsGeo();
subcriteriaCity.setLabel(location.getCity());
subcriteriaCity.setValue(location.getCity());
subcriteriaCity.setType("location");
subcriteriaCity.setSubtype("city");
FacetsGeo facetStateToAdd = new FacetsGeo();
boolean stateExists = false;
for(FacetsGeo facetState: facetCountry.getSubCriteria()) {
if(facetState.getType() != null && facetState.getSubtype() != null
&& facetState.getType().equalsIgnoreCase("location")
&& facetState.getSubtype().equalsIgnoreCase("state")
&& facetState.getValue().equalsIgnoreCase(location.getState())) {
facetStateToAdd = facetState;
if(facetStateToAdd.getSubCriteria() == null) {
facetStateToAdd.setSubCriteria(new ArrayList<FacetsGeo>());
}
stateExists = true;
break;
}
}
if(!stateExists) {
facetStateToAdd.setLabel(location.getState());
facetStateToAdd.setValue(location.getState());
facetStateToAdd.setType("location");
facetStateToAdd.setSubtype("state");
if(facetStateToAdd.getSubCriteria() == null) {
facetStateToAdd.setSubCriteria(new ArrayList<SearchBarFacets>());
}
facetStateToAdd.getSubCriteria().add(subcriteriaCity);
facetCountry.getSubCriteria().add(facetStateToAdd);
} else {
facetStateToAdd.getSubCriteria().add(subcriteriaCity);
facetCountry.getSubCriteria().add(facetStateToAdd);
}
}
}
}
}`
Para una solución de Java 8 Streaming, se puede hacer, como a continuación.
Esta solución particular no genera exactamente la misma JSON se muestra en la cuestión, porque no creo que una gran variedad de objetos de estado, con 1 llave por objeto nombrar el estado, es una buena estructura JSON.
Si el JSON debe ser como se muestra en la pregunta, a continuación, esta solución le dará un buen comienzo para llegar allí.
Set<Location> locationSet = Set.of(
new Location("USA", "AZ", "Phoenix"),
new Location("USA", "AZ", "Scottsdale"),
new Location("USA", "AZ", "Peoria"),
new Location("USA", "MD", "Baltimore"),
new Location("USA", "MD", "Gaithersburg"),
new Location("USA", "MD", "OwingsMills"),
new Location("CA", "ON", "Toronto"));
Map<String, Map<String, List<String>>> countryMap = locationSet.stream()
.collect(Collectors.groupingBy(Location::getCountry, TreeMap::new,
Collectors.groupingBy(Location::getState, TreeMap::new,
Collectors.mapping(Location::getCity, Collectors.toList()))));
System.out.println(JSONWriter.valueToString(countryMap));
Salida
{"CA":{"ON":["Toronto"]},"USA":{"AZ":["Phoenix","Scottsdale","Peoria"],"MD":["OwingsMills","Baltimore","Gaithersburg"]}}