JSON numerikus felsorolás perzisztálása
Címkék: Java SQL Hibernate JPA Numerikus lista
2022.11.14. 11:45
A JAVA fejlesztés terén egyre nagyobb szerepet kapnak a támogató eszközök. Többek között az ORM.. JAVA esetén leginkább a JPA, a Hibernate, és a Spring Data bűvös neveket lehet hallani. Persze ezek részben átfedésben vannak.
Évekkel ezelőtt tanácsot kértünk kollégánk, akkor már egy neves cégnél dolgozó gyermekétől, hogy adattárolás (perzisztencia) terén milyen irányba induljunk tovább. Felvetettük a Hibernate használatát. Azt a választ kaptuk, hogy egyes esetekben nehézkes a használata. Nehezen lehet elérni, hogy a Hibernate megértse mit szeretnénk tőle. Sajnos akkor nem tudakoltuk meg mibe is futottak bele.
Most magam is belefutottam olyan problémába, amely eszembe juttatta az esetet. Bizonyára az elmúlt idő is hozott fejlődést, de az elsőre problémás feladatot is sikerült megoldani.
A feladat a következő. JSON struktúrát kell feldolgozni. A struktúra tartalmaz egy numerikus adatok felsorolását tartalmazó nodot. Másként fogalmazva numerikus adatok tömbjét tartalmazza. Kikötés. hogy ezen lista sorrendjét meg kell tartani.
Magától értetődőnek tűnt, hogy master - details (one to many) megközelítést alkalmazzak. A master entitásban létrehoztam egy List<Long> típusú membert. Erre helyeztem el a megfelelő annotációkat.Persze a megfelelő details entitást is létrehoztam. Az autó konfiguráció kiakadt nem tudta felépíteni a konstrukciót. Nem értettem meg a probléma okát. Néztem a neten, látszólag jól csináltam. Persze nem, de erről kicsit később.
Megnéztem, volna e más megoldás. Akad az @ElementCollection használata. Az @ElementCollection által létrehozott details tábla, alapesetben, csak a master idegenkulcsát és az értéket tartalmazza, sorrendi információt nem. Mint tudható SQL esetén a rendezetlen select sorrendje esetleges.
Két módon hidalható át a probléma. A JSON parselolását meg kell támogatni map-á alakítással, és a master struktúrában Map<Integer, Long> membert kell használni.
@JsonDeserialize(using = ListToHashtableDeserializer.class)
@ElementCollection
@CollectionTable(name = "SERIES_DATA", joinColumns = @JoinColumn(name = "SERIES_ID"))
@MapKeyColumn(name = "DATA_ID")
@Column(name = "VALUE")
Map<Integer, Long> series;
import java.io.IOException;
import java.util.Iterator;
import java.util.LinkedHashMap;import com.fasterxml.jackson.core.JacksonException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.ObjectCodec;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonNode;public class ListToHashtableDeserializer extends JsonDeserializer<LinkedHashMap<Integer, Long>> {
@Override
public LinkedHashMap<Integer, Long> deserialize(JsonParser parser, DeserializationContext ctxt) throws IOException, JacksonException {
ObjectCodec codec = parser.getCodec();
JsonNode node = codec.readTree(parser);
Iterator<JsonNode> subNodesIterator = node.elements();
LinkedHashMap<Integer, Long> result = new LinkedHashMap<>();
int index = 0;
while (subNodesIterator.hasNext()) {
JsonNode innerNode = subNodesIterator.next();
Long data = innerNode.asLong();
result.put(index, data);
index += 1;
}
return result;
}
}
Vagy a List<Long> megtartása mellett a @OrderColumn használatával. Na ez elegáns és a kívánt eredményre vezet.
@ElementCollection
@CollectionTable(name = "SERIES_DATA", joinColumns = @JoinColumn(name = "SERIES_ID"))
@OrderColumn
List<Long> series;
Persze az élet nem áll meg. Kiderült, hogy az adattételekhez kapcsoltan további információ tárolására lesz szükség, ezért vissza kellett térni a one to many megoldásra.
Feltűnt, hogy az összes példa saját objektumot használ listaelemként. Így már gyanús lett és meg is találtam a kulcs mondatot. A details entitás osztálynak rendelkeznie kell paraméter nélküli konstruktorral.
@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
@ManyToOne(fetch = FetchType.LAZY, optional = false)
@JoinColumn(name="series_id", nullable = false)
TimeSeries timeSeries;
...
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "data_id")
private Long id;@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
@ManyToOne(fetch = FetchType.LAZY, optional = false)
@JoinColumn(name="series_id", nullable = false)
TimeSeries timeSeries;
...
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;import com.fasterxml.jackson.core.JacksonException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.ObjectCodec;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonNode;
import com.reg.time_series.entity.SeriesData;public class ListToSeriesDataDeserializer extends JsonDeserializer<List<SeriesData>> {
@Override
public List<SeriesData> deserialize(JsonParser parser, DeserializationContext ctxt) throws IOException, JacksonException {
ObjectCodec codec = parser.getCodec();
JsonNode node = codec.readTree(parser);
Iterator<JsonNode> subNodesIterator = node.elements();
List<SeriesData> result = new ArrayList<>();
int index = 0;
while (subNodesIterator.hasNext()) {
JsonNode innerNode = subNodesIterator.next();
Long data = innerNode.asLong();
SeriesData SeriesData = new SeriesData(index, data);
result.add(SeriesData);
index += 1;
}
return result;
}
}
A bejegyzés trackback címe:
Kommentek:
A hozzászólások a vonatkozó jogszabályok értelmében felhasználói tartalomnak minősülnek, értük a szolgáltatás technikai üzemeltetője semmilyen felelősséget nem vállal, azokat nem ellenőrzi. Kifogás esetén forduljon a blog szerkesztőjéhez. Részletek a Felhasználási feltételekben és az adatvédelmi tájékoztatóban.