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;

Ehhez szükség van egy deserializer osztályra:

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.

A master osztályban így jelenik meg:

@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
@ManyToOne(fetch = FetchType.LAZY, optional = false)
@JoinColumn(name="series_id", nullable = false)
TimeSeries timeSeries;

A JsonProperty.Access.WRITE_ONLY eredményezi, hogy ezt a tulajdonságot, csak a JSON struktúra deszérializálása során kell feldolgozni, előállítani.

A detail (child) osztályban pedig így:

...
@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;
...

Persze ehhez is kell egy deserializer osztály:

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;
}

}

Sajnos nem jöttem rá, hogyan lehet a forrást szépen, behúzással megjeleníteni

A bejegyzés trackback címe:

https://pharsan.blog.hu/api/trackback/id/tr1917978152

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.

Nincsenek hozzászólások.
süti beállítások módosítása