Referencje w formacie JSON

0

Czy jest możliwe w pliku JSON utworzenie referencji do obiektu wcześniej zapisanego w nim?

klasy wzorcowe:

public class Conflict
{	
	private Alliance initiatorAlliance, reactorAlliance;
	private ArrayList<State> initiatorInvolvedStates,reactorInvolvedStates;

	public Conflict()
	{
	}

	...
}
public class Alliance
{	
	private int leaderId;
	ArrayList<State> members;

	public Alliance()
	{
	}

	...
}

Plik conflict.json:

{
	"initiatorAlliance" :
	{
		"leaderId" : 1,
		
		"members" :
		[
			{
				"name" : "INITIATOR ALLY 0",
				"id" : 0,
			},
			
			{
				"name" : "INITIATOR ALLY 1",
				"id" : 1,
			},
		],
	},
	
	"reactorAlliance" :
	{
		"leaderId" : 2,
		
		"members" :
		[
			{
				"name" : "REACTOR ALLY 0",
				"id" : 2,
			},
			
			{
				"name" : "REACTOR ALLY 1",
				"id" : 3,
			},
			
			{
				"name" : "REACTOR ALLY 2",
				"id" : 4,
			},
		],
	},
	
	"inititorInvolvedAllies" :
	[
		// Tutaj chciałbym dodać referencje do np. "INITIATOR ALLY 0"
	],
	
	"reactorInvolvedAllies" :
	[
	],
}

Jeśli nie to czy istnieje inny sposób by to zrobić? Potrzebne mi to do testów jednostkowych, więc chciałbym by nie zmieniły się one w integracyjne. Jak radzicie sobie z podbnymi sytuacjami w testach jednostkowych?

1

Json i testy jednostkowe - brzmi bardzo zle. Napisz jakie to testy i co chcesz osiągnąć.

0

Próbuje utworzyć z JSONa testowaną klasę. Kod jest oczywiście dużo większy. To, co wkleiłem to tylko niewielki wycinek z gry, którą tworzę. Ładuje to z JSONa, bo testowana klasa Conflict.java zawiera dużo innych obiektów np. State.java, które nie są wszystkie w konstruktorze podane i w czasie gry pewne obiekty State mogą być dodane lub odjęte. Chce napisać testy jednostkowe do klasy Conflict.java.

0
blekot napisał(a):

Ładuje to z JSONa, bo testowana klasa Conflict.java zawiera dużo innych obiektów np. State.java, które nie są wszystkie w konstruktorze podane i w czasie gry pewne obiekty State mogą być dodane lub odjęte

Brzmi to bardzo źle. Podsumowując ponieważ masz tak napisany kod że nie jesteś w stanie ustawiać wartości żeby to przetestować postanowiłeś serializować i deserializować klasę?
A nie prościej przerobić oryginalną klasę żeby stała się testowalna?

Odpowiadając na twoje pytanie - nie, Json to nie Yaml i nie ma referencji. Trzeba robić kopiuj wklej, lub przejść na Yamla lub zrobić to porządnie i zmienić kod klasy którą chcesz testować

2

@blekot deserializowanie testowanej klasy z JSONa żeby przetestować jednostkowo to bardzo słaby pomysł. Jeśli serializujesz / deserializujesz WYŁĄCZNIE do testów (a nie po to, by np. zapisać stan gry trzymany w POJO czy coś) to jest wręcz tragiczny pomysł.

Spróbuj zacząć pisać sobie testy do tego tak, jakbyś był w stanie testować to bez serializacji/deserializacji. Po drodze zacznie Ci wychodzić, co jest do zmiany / wywalenia / dodania żeby dało się to testować.

bo testowana klasa Conflict.java zawiera dużo innych obiektów np. State.java, które nie są wszystkie w konstruktorze podane i w czasie gry pewne obiekty State mogą być dodane lub odjęte. Chce napisać testy jednostkowe do klasy Conflict.java.

Przede wszystkim to brzmi tak, jakby ten Conflict.java był jakimś god objectem, który trzyma wszystko i teraz sobie z nim nie radzisz. Odpowiada za trzymanie stanu gry, zmienianie stanu gry, przejścia od stanu A do B i co się jeszcze da - może trzeba zacząć od rozbicia go i podzielenia odpowiedzialności.

Przez to, że masz taki wielki worek na wszystko i ze wszystkim, nie jesteś w stanie testować tego jednostkowo - tzn. samo zbudowanie tego stanu początkowego już jest pewnie dość karkołomne i stąd kombinacje z deserializacją. Twoim celem powinno być doprowadzenie do takiej sytuacji, w której przygotowanie jednostki pod test (nadanie jej stanu początkowego itd) będzie w miarę proste.

KamilAdam napisał(a):

Odpowiadając na twoje pytanie - nie, Json to nie Yaml i nie ma referencji. Trzeba robić kopiuj wklej, lub przejść na Yamla lub zrobić to porządnie i zmienić kod klasy którą chcesz testować

To akurat nie jest do końca prawdą. Znaczy - oficjalnie czegoś takiego nie ma, istnieje co najmniej kilka propozycji dla wsparcia referencji w JSON, mniej lub bardziej używanych.

Był nawet draft standardu dla referencji w JSON, tylko chyba niestety pozostał draftem:
https://tools.ietf.org/html/draft-pbryan-zyp-json-ref-03

W każdym razie Jackson pozwala jakoś-tam to rozwiązać bez kopiuj-wklej, Swagger ma atrybut $ref na tego typu przypadki, różne libki np. JSON Spec również. Generalnie wygląda na to, że Swagger, JSON Spec i ten upadły draft korzystają z atrybutu $ref i odwołują się do specyfikacji URI: RFC 3986 więc można to chyba potraktować jak pewien trop.

0

Przede wszystkim to brzmi tak, jakby ten Conflict.java był jakimś god objectem, który trzyma wszystko i teraz sobie z nim nie radzisz.>

Dla uproszczenia niedokońca napisałem prawdę tzn. nie Conflict.java, ale ma ona w sobie taki obiekt - GameDataBase.java, który rzeczywiście przechowuje w sobie chyba wszystko(państwa, armie, szlaki handlowe etc.) i jest takim god objectem. Do działania wielu klas ten obiekt jest niezbędny. Posiada on jedynie metody obsługujące dodawanie lub usuwanie wspomnianych obiektów. Jest on czymś w rodzaju Singletona tyle, że nie jest statycznym obiektem. Przekazuje go innym klasom zazwyczaj w konstruktorze, a one wybierają z niego co im potrzeba. To jak trafnie stwierdziłeś prowadzi do karkołomnych inicjalizacji w testach. Klasa Conflict.java ma 330, a Alliance.java ma 160 linii. Myśle, że nie wymagają wydzielania z nich kolejnych klas.

Jeśli więc zastosowanie takiego podejścia z wykorzystaniem god objectu, czyli mojej bazy danych gry jest złe, to dla mnie jak odgaduje oznacza to spore kłopoty. Co powinienem zrobić? Jakieś sugestie?

@superdurszlak także znalazłem te informacje o referencjach w JSONie. Jednak nie są mi znane inne parsery tego formatu. Korzystam, z tego od libgdx(framework do gamedevu), a ten jak na razie wynika z moich prób nie obsługuje $ref.

2
blekot napisał(a):

Jeśli więc zastosowanie takiego podejścia z wykorzystaniem god objectu, czyli mojej bazy danych gry jest złe, to dla mnie jak odgaduje oznacza to spore kłopoty. Co powinienem zrobić? Jakieś sugestie?

Przypuszczam, że trzeba po prostu rozbić ten god object na mniejsze kawałki tak, żeby przestał nim być. Jeśli dobrze rozumiem, celem jego istnienia jest trzymanie stanu gry w pamięci? Może nie musisz trzymać całego stanu w jednym obiekcie, a jeśli już chcesz mieć taki agregat na całość stanu, to wydzielić z niego mniejsze fragmenty, nie dawać klasom zależnym bezpośredniego dostępu do stanu tylko schować to za mniejszymi interfejsami do interakcji ze stanem i z nich porobić zależności...

@superdurszlak także znalazłem te informacje o referencjach w JSONie. Jednak nie są mi znane inne parsery tego formatu. Korzystam, z tego od libgdx(framework do gamedevu), a ten jak na razie wynika z moich prób nie obsługuje $ref.

Jackson pozwala obsługiwać referencje, ale w inny sposób. Nie wiem, czy Gson ma coś podobnego, nie wiem czego używa libgdx do serializacji. Jackson pozwala rozwiązywać m.in. cykliczne referencje, czy referencje do innych obiektów poprzez adnotacje np. @JsonIdentityInfo

0

Jeśli dobrze rozumiem, celem jego istnienia jest trzymanie stanu gry w pamięci?

Tak, jest w nim zawarty głównie stan gry i parę innych rzeczy, które przydałoby się wydzielić. Nie mniej jednak koncepcja ze stworzeniem interfejsów dostępowych do stanów gry wydaje mi się bardziej realna do zrobienia. To spory projekt, a ja niestety nie mam tyle czasu, by poprawić to, jak należy. Być może w przyszłości odpokutuje za takie podejście. Dzięki za pomoc. Łapki w górę do twoich postów.

1 użytkowników online, w tym zalogowanych: 0, gości: 1