Skip to content
Snippets Groups Projects
Commit 942433d1 authored by Hallvard Trætteberg's avatar Hallvard Trætteberg
Browse files

Mer forenkling og dokumentasjon.

parent bd4b5765
No related branches found
No related tags found
No related merge requests found
Showing
with 111 additions and 84 deletions
# Simpleexample
Dette prosjektet er et eksempel på en nokså minimalistisk trelagsapplikasjon, altså med et domenelag, brukergrensesnitt (UI) og persistens (lagring). Prosjektet inneholder tester for alle lagene, med rimelig god dekningsgrad. Prosjektet er konfigurert med gradle som byggesystem.
## Organisering av koden
Prosjektet er organisert med 2 * 2 = 4 kildekodemapper, kode og ressurser for henholdsvis applikasjonen selv og testene:
- **src/main/java** for koden til applikasjonen
- **src/main/resources** for tilhørende ressurser, f.eks. data-filer og FXML-filer, som brukes av applikasjonen.
- **src/test/java** for testkoden
- **src/test/resources** for tilhørende ressurser, f.eks. data-filer og FXML-filer, som brukes av testene.
Dette er en vanlig organisering for prosjekter som bygges med gradle (og maven).
## Domenelaget
Domenelaget inneholder alle klasser og logikk knyttet til dataene som applikasjonen handler om og håndterer. Dette laget skal være helt uavhengig av brukergrensesnittet eller lagingsteknikken som brukes.
Vår app handler om samlinger av såkalte geo-lokasjoner, altså steder identifisert med lengde- og breddegrader. Domenelaget inneholder klasser for å representere og håndtere slike, og disse finnes i **[simpleex.core](src/main/java/simpleex/core/README.md)**-pakken.
## Brukergrensesnittlaget
Brukergrensesnittlaget inneholder alle klasser og logikk knyttet til visning og handlinger på dataene i domenelaget. Brukergrensesnittet til vår app viser frem en liste av geo-lokasjoner, den som velges vises på et kart. En flytte og legge til geo-lokasjoner. Samlingen med geo-lokasjoner kan lagres og evt. leses inn igjen.
Brukergrensesnittet er laget med JavaFX og FXML og finnes i **[simpleex.ui](src/main/java/simpleex/ui/README.md)**-pakken (JavaFX-koden i **src/main/java** og FXML-filen i **src/main/resources**)
## Persistenslaget
Persistenslaget inneholder alle klasser og logikk for lagring (skriving og lesing) av dataene i domenelaget. Vårt persistenslag implementerer fillagring med JSON-syntaks.
Persistenslaget finnes i **[simpleex.json](src/main/java/simpleex/json/README.md)**-pakken.
## Bygging med gradle
# Source package for core code
\ No newline at end of file
# Kildekode for domenelaget
Domenelaget utgjøres av en samling av geo-lokasjoner representert vha. to klasse:
- LatLong - en geo-lokasjon, representert vha. lengde og breddegrad
- LatLongs - en samling LatLong-objekter
```plantuml
class LatLong {
double latitude
double longitude
}
class LatLongs
LatLongs *--> "*" LatLong: "latLongs"
```
package simpleex.json;
import com.fasterxml.jackson.databind.Module;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import simpleex.core.LatLong;
import simpleex.core.LatLongs;
public class JacksonConfigurator {
public ObjectMapper createObjectMapper() {
final ObjectMapper objectMapper = new ObjectMapper();
configureObjectMapper(objectMapper);
return objectMapper;
}
public void configureObjectMapper(final ObjectMapper objectMapper) {
objectMapper.registerModule(createModule());
}
public Module createModule() {
final SimpleModule module = new SimpleModule();
configureModule(module);
return module;
}
public void configureModule(final SimpleModule module) {
module.addSerializer(LatLong.class, new LatLongSerializer());
module.addSerializer(LatLongs.class, new LatLongsSerializer());
module.addDeserializer(LatLong.class, new LatLongDeserializer());
module.addDeserializer(LatLongs.class, new LatLongsDeserializer());
}
}
# Resources used by the web server code
\ No newline at end of file
# Kildekode for persistenslaget
Persistenslaget bruker [Jackson-biblioteket](https://github.com/FasterXML/jackson) for å serialisere objekter til [JSON](https://www.json.org).
For hver [domeneklasse](../core/README.md) finnes tilsvarende klasser for serialisering (konvertering av domeneobjekter til tekststrøm) og deserialisering (parsing av tekststrøm og opprettelse av tilsvarende domeneobjekter). I tillegg finnes det en klasse, **JacksonConfigurator**, som inneholder diverse metoder for å lage og konfigurere **ObjectMapper**- og **SimpleModule**-objektene som trengs for å serialisere og deserialisere objekter.
package simpleex.ui;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import fxmapcontrol.Location;
import fxmapcontrol.MapBase;
import fxmapcontrol.MapItemsControl;
......@@ -27,10 +26,7 @@ import javafx.scene.control.Slider;
import javafx.stage.FileChooser;
import simpleex.core.LatLong;
import simpleex.core.LatLongs;
import simpleex.json.LatLongDeserializer;
import simpleex.json.LatLongSerializer;
import simpleex.json.LatLongsDeserializer;
import simpleex.json.LatLongsSerializer;
import simpleex.json.JacksonConfigurator;
public class FxAppController {
......@@ -193,13 +189,7 @@ public class FxAppController {
public ObjectMapper getObjectMapper() {
if (objectMapper == null) {
final SimpleModule module = new SimpleModule();
module.addSerializer(LatLong.class, new LatLongSerializer());
module.addSerializer(LatLongs.class, new LatLongsSerializer());
module.addDeserializer(LatLong.class, new LatLongDeserializer());
module.addDeserializer(LatLongs.class, new LatLongsDeserializer());
objectMapper = new ObjectMapper();
objectMapper.registerModule(module);
objectMapper = new JacksonConfigurator().createObjectMapper();
}
return objectMapper;
}
......
# The UI source code, a minimal JavaFX/FXML UI
\ No newline at end of file
# Kildekode for brukergrensesnittet
Brukergrensesnittet er laget med JavaFX og FXML.
Brukergrensesnittet er enkelt og består av en liste og et kart. Lista viser innholdet i et **LatLongs**-objekt, altså en samling **LatLong**-objekter. Når man velger et element, så vises det elementet som et punkt på kartet. En kan flytte punktet, forskyve kartet, zoome inn og ut og opprette nye **LatLong**-objekter.
Kartet implementeres av ([FxMapControl](https://github.com/ClemensFischer/FX-Map-Control), og siden biblioteket ikke er tilgjengelig i et sentral repository, så har vi bygget og lagt ved jar-filen.
I tillegg kan en lagre og lese inn **LatLongs**-objektet fra **Open...**- og **Save...**-aksjoner i en **File**-meny.
# Ressurser for brukergrensesnittet
Brukergrensesnittet er laget med JavaFX og FXML, og her ligger FXML-fila som brukes.
# Testkode for domenelaget
package simpleex.json;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import java.io.IOException;
import org.junit.Assert;
public abstract class AbstractJsonTest {
private ObjectMapper objectMapper;
private final ObjectMapper objectMapper = new JacksonConfigurator().createObjectMapper();
public ObjectMapper getObjectMapper() {
return objectMapper;
}
protected void setUp() {
objectMapper = createObjectMapper();
}
protected abstract ObjectMapper createObjectMapper();
protected <T> ObjectMapper createObjectMapper(final Class<T> clazz,
final JsonSerializer<T> serializer, final JsonDeserializer<T> deserializer) {
return new ObjectMapper().registerModule(createSimpleModule(clazz, serializer, deserializer));
}
protected <T> SimpleModule createSimpleModule(final Class<T> clazz,
final JsonSerializer<T> serializer, final JsonDeserializer<T> deserializer) {
return new SimpleModule().addSerializer(clazz, serializer).addDeserializer(clazz, deserializer);
}
protected void assertEqualsIgnoreWhitespace(final String expected, final String actual)
throws Exception {
Assert.assertEquals(expected, actual.replaceAll("\\s+", ""));
}
protected void assertWriteValue(final String expected, final Object value) throws Exception {
assertEqualsIgnoreWhitespace(expected, getObjectMapper().writeValueAsString(value));
}
protected <T> T readValue(final String s, final Class<T> clazz)
throws IOException, JsonParseException, JsonMappingException {
return getObjectMapper().readValue(s, clazz);
}
}
package simpleex.json;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import simpleex.core.LatLong;
public class LatLongJsonTest extends AbstractJsonTest {
@Before
@Override
public void setUp() {
super.setUp();
}
@Override
protected ObjectMapper createObjectMapper() {
return createObjectMapper(LatLong.class, new LatLongSerializer(), new LatLongDeserializer());
}
@Test
public void testLatLongSerialization() throws Exception {
assertWriteValue("{\"latitude\":63.1,\"longitude\":12.3}", new LatLong(63.1, 12.3));
assertEqualsIgnoreWhitespace("{\"latitude\":63.1,\"longitude\":12.3}", getObjectMapper().writeValueAsString(new LatLong(63.1, 12.3)));
}
@Test
public void testLatLongObjectDeserialization() throws Exception {
Assert.assertEquals(new LatLong(63.1, 12.3),
readValue("{\"latitude\":63.1,\"longitude\":12.3}", LatLong.class));
getObjectMapper().readValue("{\"latitude\":63.1,\"longitude\":12.3}", LatLong.class));
}
@Test
public void testLatLongArrayDeserialization() throws Exception {
Assert.assertEquals(new LatLong(63.1, 12.3), readValue("[ 63.1, 12.3 ]", LatLong.class));
Assert.assertEquals(new LatLong(63.1, 12.3), getObjectMapper().readValue("[ 63.1, 12.3 ]", LatLong.class));
}
}
package simpleex.json;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import simpleex.core.LatLong;
import simpleex.core.LatLongs;
public class LatLongsJsonTest extends AbstractJsonTest {
@Before
@Override
public void setUp() {
super.setUp();
}
@Override
protected ObjectMapper createObjectMapper() {
final SimpleModule module =
createSimpleModule(LatLong.class, new LatLongSerializer(), new LatLongDeserializer());
module.addSerializer(LatLongs.class, new LatLongsSerializer());
module.addDeserializer(LatLongs.class, new LatLongsDeserializer());
return new ObjectMapper().registerModule(module);
}
@Test
public void testLatLongsSerialization() throws Exception {
assertWriteValue(
assertEqualsIgnoreWhitespace(
"[{\"latitude\":63.1,\"longitude\":12.3},{\"latitude\":63.0,\"longitude\":12.4}]",
new LatLongs(new LatLong(63.1, 12.3), new LatLong(63.0, 12.4)));
getObjectMapper().writeValueAsString(new LatLongs(new LatLong(63.1, 12.3), new LatLong(63.0, 12.4))));
}
@Test
public void testLatLongsDeserialization() throws Exception {
final LatLongs latLongs =
readValue("[{\"latitude\":63.1,\"longitude\":12.3}, [63.0,12.4]]", LatLongs.class);
getObjectMapper().readValue("[{\"latitude\":63.1,\"longitude\":12.3}, [63.0,12.4]]", LatLongs.class);
Assert.assertEquals(2, latLongs.getLatLongCount());
Assert.assertEquals(new LatLong(63.1, 12.3), latLongs.getLatLong(0));
Assert.assertEquals(new LatLong(63.0, 12.4), latLongs.getLatLong(1));
......
# Testkode for persistenslaget
# Testkode for brukergrensesnittet
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment