Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* Copyright 2016-2023 Berry Cloud Ltd. All rights reserved.
*/

package dev.learning.xapi.jackson;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import java.io.IOException;
import java.util.Locale;
import java.util.Map;

/**
* Specific Locale serializer using {@link Locale#toLanguageTag()} instead of
* {@link Locale#toString()}.
*
* @author István Rátkai (Selindek)
*/
public class LocaleSerializer extends StdSerializer<Locale> {

private static final long serialVersionUID = 7182941951585541965L;

public LocaleSerializer() {
super(Locale.class);
}

@Override
public void serialize(Locale value, JsonGenerator gen, SerializerProvider provider)
throws IOException {
gen.writeString(value.toLanguageTag());
}

/**
* <p>
* Locale Key Serializer.
* </p>
* For serializing Locale keys in {@link Map}s
*
* @author István Rátkai (Selindek)
*/
public static class LocaleKeySerializer extends StdSerializer<Locale> {

private static final long serialVersionUID = 7182941951585541965L;

public LocaleKeySerializer() {
super(Locale.class);
}

@Override
public void serialize(Locale value, JsonGenerator gen, SerializerProvider provider)
throws IOException {
gen.writeFieldName(value.toLanguageTag());
}

}

}
3 changes: 3 additions & 0 deletions xapi-model/src/main/java/dev/learning/xapi/model/Context.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import dev.learning.xapi.jackson.LocaleSerializer;
import dev.learning.xapi.model.validation.constraints.HasScheme;
import dev.learning.xapi.model.validation.constraints.NotUndetermined;
import dev.learning.xapi.model.validation.constraints.ValidActor;
Expand Down Expand Up @@ -73,6 +75,7 @@ public class Context {
* The language in which the experience being recorded in this Statement (mainly) occurred in.
*/
@NotUndetermined
@JsonSerialize(using = LocaleSerializer.class)
private Locale language;

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

package dev.learning.xapi.model;

import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import dev.learning.xapi.jackson.LocaleSerializer;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
Expand All @@ -20,6 +22,7 @@
* @see <a href="https://github.com/adlnet/xAPI-Spec/blob/master/xAPI-Data.md#lang-maps">Language
* Maps</a>
*/
@JsonSerialize(keyUsing = LocaleSerializer.LocaleKeySerializer.class)
public class LanguageMap extends LinkedHashMap<Locale, String> {

private static final long serialVersionUID = 7375610804995032187L;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ void whenDeserializingActivityDefinitionThenNameIsExpected() throws Exception {
final ActivityDefinition result = objectMapper.readValue(file, ActivityDefinition.class);

// Then Name Is Expected
assertThat(result.getName().get(Locale.ENGLISH),
assertThat(result.getName().get(Locale.US),
is("Does the xAPI include the concept of statements?"));

}
Expand All @@ -129,7 +129,7 @@ void whenDeserializingActivityDefinitionThenDescriptionIsExpected() throws Excep
final ActivityDefinition result = objectMapper.readValue(file, ActivityDefinition.class);

// Then Description Is Expected
assertThat(result.getDescription().get(Locale.ENGLISH), is("pong[.]1:[,]dg[.]:10[,]lunch[.]"));
assertThat(result.getDescription().get(Locale.US), is("pong[.]1:[,]dg[.]:10[,]lunch[.]"));

}

Expand Down Expand Up @@ -188,7 +188,7 @@ void whenDeserializingActivityDefinitionWithChoicesThenChoicesDescriptionIsExpec
final ActivityDefinition result = objectMapper.readValue(file, ActivityDefinition.class);

// Then Choices Description Is Expected
assertThat(result.getChoices().get(0).getDescription().get(Locale.ENGLISH),
assertThat(result.getChoices().get(0).getDescription().get(Locale.US),
is("Does the xAPI include the concept of statements?"));

}
Expand Down Expand Up @@ -218,7 +218,7 @@ void whenDeserializingActivityDefinitionWithScaledThenScaleDescriptionIsExpected
final ActivityDefinition result = objectMapper.readValue(file, ActivityDefinition.class);

// Then Scale Description Is Expected
assertThat(result.getScale().get(0).getDescription().get(Locale.ENGLISH),
assertThat(result.getScale().get(0).getDescription().get(Locale.US),
is("Does the xAPI include the concept of statements?"));

}
Expand Down Expand Up @@ -248,7 +248,7 @@ void whenDeserializingActivityDefinitionWithSourceThenSourceDescriptionIsExpecte
final ActivityDefinition result = objectMapper.readValue(file, ActivityDefinition.class);

// Then Source Description Is Expected
assertThat(result.getSource().get(0).getDescription().get(Locale.ENGLISH),
assertThat(result.getSource().get(0).getDescription().get(Locale.US),
is("Does the xAPI include the concept of statements?"));

}
Expand Down Expand Up @@ -278,7 +278,7 @@ void whenDeserializingActivityDefinitionWithTargetThenTargetDescriptionIsExpecte
final ActivityDefinition result = objectMapper.readValue(file, ActivityDefinition.class);

// Then Target Description Is Expected
assertThat(result.getTarget().get(0).getDescription().get(Locale.ENGLISH),
assertThat(result.getTarget().get(0).getDescription().get(Locale.US),
is("Does the xAPI include the concept of statements?"));

}
Expand Down Expand Up @@ -308,7 +308,7 @@ void whenDeserializingActivityDefinitionWithStepsThenStepsDescriptionIsExpected(
final ActivityDefinition result = objectMapper.readValue(file, ActivityDefinition.class);

// Then Steps Description Is Expected
assertThat(result.getSteps().get(0).getDescription().get(Locale.ENGLISH),
assertThat(result.getSteps().get(0).getDescription().get(Locale.US),
is("Does the xAPI include the concept of statements?"));

}
Expand All @@ -319,9 +319,9 @@ void whenSerializingActivityDefinitionOfInteractionTypeTrueFalseThenResultIsEqua

final ActivityDefinition activityDefinition = ActivityDefinition.builder()

.addName(Locale.ENGLISH, "True false question")
.addName(Locale.US, "True false question")

.addDescription(Locale.ENGLISH, "Does the xAPI include the concept of statements?")
.addDescription(Locale.US, "Does the xAPI include the concept of statements?")

.interactionType(InteractionType.TRUE_FALSE)

Expand All @@ -347,21 +347,21 @@ void whenSerializingActivityDefinitionOfInteractionTypeChoiceThenResultIsEqualTo

final ActivityDefinition activityDefinition = ActivityDefinition.builder()

.addName(Locale.ENGLISH, "Choice")
.addName(Locale.US, "Choice")

.addDescription(Locale.ENGLISH, "Which of these prototypes are available at the beta site?")
.addDescription(Locale.US, "Which of these prototypes are available at the beta site?")

.interactionType(InteractionType.CHOICE)

.correctResponsesPattern(Collections.singletonList("golf[,]tetris"))

.addChoice(c -> c.id("golf").addDescription(Locale.ENGLISH, "Golf Example"))
.addChoice(c -> c.id("golf").addDescription(Locale.US, "Golf Example"))

.addChoice(c -> c.id("facebook").addDescription(Locale.ENGLISH, "Facebook App"))
.addChoice(c -> c.id("facebook").addDescription(Locale.US, "Facebook App"))

.addChoice(c -> c.id("tetris").addDescription(Locale.ENGLISH, "Tetris Example"))
.addChoice(c -> c.id("tetris").addDescription(Locale.US, "Tetris Example"))

.addChoice(c -> c.id("scrabble").addDescription(Locale.ENGLISH, "Scrabble Example"))
.addChoice(c -> c.id("scrabble").addDescription(Locale.US, "Scrabble Example"))

.type(URI.create("http://adlnet.gov/expapi/activities/cmi.interaction"))

Expand Down Expand Up @@ -389,7 +389,7 @@ void whenCallingToStringThenResultIsExpected() throws Exception {

// Then Result Is Expected
assertThat(result, is(
"ActivityDefinition(name={en=Does the xAPI include the concept of statements?}, description={en=pong[.]1:[,]dg[.]:10[,]lunch[.]}, type=http://adlnet.gov/expapi/activities/cmi.interaction, moreInfo=http://example.com/more, interactionType=TRUE_FALSE, correctResponsesPattern=[{case_matters=false}{lang=en}To store and provide access to learning experiences.], choices=[InteractionComponent(id=1, description={en=Does the xAPI include the concept of statements?})], scale=[InteractionComponent(id=1, description={en=Does the xAPI include the concept of statements?})], source=[InteractionComponent(id=1, description={en=Does the xAPI include the concept of statements?})], target=[InteractionComponent(id=1, description={en=Does the xAPI include the concept of statements?})], steps=[InteractionComponent(id=1, description={en=Does the xAPI include the concept of statements?})], extensions={http://url=www.example.com})"));
"ActivityDefinition(name={en_US=Does the xAPI include the concept of statements?}, description={en_US=pong[.]1:[,]dg[.]:10[,]lunch[.]}, type=http://adlnet.gov/expapi/activities/cmi.interaction, moreInfo=http://example.com/more, interactionType=TRUE_FALSE, correctResponsesPattern=[{case_matters=false}{lang=en}To store and provide access to learning experiences.], choices=[InteractionComponent(id=1, description={en_US=Does the xAPI include the concept of statements?})], scale=[InteractionComponent(id=1, description={en_US=Does the xAPI include the concept of statements?})], source=[InteractionComponent(id=1, description={en_US=Does the xAPI include the concept of statements?})], target=[InteractionComponent(id=1, description={en_US=Does the xAPI include the concept of statements?})], steps=[InteractionComponent(id=1, description={en_US=Does the xAPI include the concept of statements?})], extensions={http://url=www.example.com})"));
}

@Test
Expand All @@ -398,11 +398,11 @@ void whenBuildingActivityDefinitionWithTwoNameValuesThenNameLanguageMapHasTwoEnt
// When Building ActivityDefinition With Two Name Values
final ActivityDefinition activityDefinition = ActivityDefinition.builder()

.addName(Locale.ENGLISH, "True false question")
.addName(Locale.US, "True false question")

.addName(Locale.GERMAN, "Richtig / Falsch-Frage")

.addDescription(Locale.ENGLISH, "Does the xAPI include the concept of statements?")
.addDescription(Locale.US, "Does the xAPI include the concept of statements?")

.interactionType(InteractionType.TRUE_FALSE)

Expand All @@ -423,9 +423,9 @@ void whenBuildingActivityDefinitionWithTwoDescriptionValuesThenDescriptionLangua
// When Building ActivityDefinition With Two Description Values
final ActivityDefinition activityDefinition = ActivityDefinition.builder()

.addName(Locale.ENGLISH, "True false question")
.addName(Locale.US, "True false question")

.addDescription(Locale.ENGLISH, "Does the xAPI include the concept of statements?")
.addDescription(Locale.US, "Does the xAPI include the concept of statements?")

.addDescription(Locale.GERMAN, "Enthält die xAPI das Konzept von Anweisungen?")

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,9 @@ void whenSerializingActivityThenResultIsEqualToExpectedJson() throws IOException

.definition(d -> d

.addName(Locale.ENGLISH, "simple statement")
.addName(Locale.US, "simple statement")

.addDescription(Locale.ENGLISH,
.addDescription(Locale.US,
"A simple Experience API statement. Note that the LRS does not need to have any prior information about the Actor (learner), the verb, or the Activity/object."))

.build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ void whenDeserializingContextThenLanguageIsExpected() throws Exception {
final Context result = objectMapper.readValue(file, Context.class);

// Then Language Is Expected
assertThat(result.getLanguage(), is(Locale.ENGLISH));
assertThat(result.getLanguage(), is(Locale.US));

}

Expand Down Expand Up @@ -230,7 +230,7 @@ void whenSerializingContextThenResultIsEqualToExpectedJson() throws IOException

.platform("platform")

.language(Locale.ENGLISH)
.language(Locale.US)

.statementReference(s -> s.id(UUID.fromString("e9b6b9ed-ef48-4986-9b86-2ef697578bf7")))

Expand Down Expand Up @@ -268,7 +268,7 @@ void whenCallingToStringThenResultIsExpected() throws IOException {

// Then Result Is Expected
assertThat(result, is(
"Context(registration=1d527164-ed0d-4b1d-9f9b-39aab0e4a089, instructor=Agent(super=Actor(name=Andrew Downes, mbox=mailto:andrew@example.co.uk, mboxSha1sum=null, openid=null, account=null)), team=Group(super=Actor(name=Example Group, mbox=null, mboxSha1sum=null, openid=null, account=null), member=null), contextActivities=ContextActivities(parent=[Activity(id=https://example.com/activity/1, definition=null)], grouping=[Activity(id=https://example.com/activity/2, definition=null)], category=[Activity(id=https://example.com/activity/3, definition=null)], other=[Activity(id=https://example.com/activity/4, definition=null)]), revision=revision, platform=platform, language=en, statement=StatementReference(id=e9b6b9ed-ef48-4986-9b86-2ef697578bf7), extensions={http://url=www.example.com})"));
"Context(registration=1d527164-ed0d-4b1d-9f9b-39aab0e4a089, instructor=Agent(super=Actor(name=Andrew Downes, mbox=mailto:andrew@example.co.uk, mboxSha1sum=null, openid=null, account=null)), team=Group(super=Actor(name=Example Group, mbox=null, mboxSha1sum=null, openid=null, account=null), member=null), contextActivities=ContextActivities(parent=[Activity(id=https://example.com/activity/1, definition=null)], grouping=[Activity(id=https://example.com/activity/2, definition=null)], category=[Activity(id=https://example.com/activity/3, definition=null)], other=[Activity(id=https://example.com/activity/4, definition=null)]), revision=revision, platform=platform, language=en_US, statement=StatementReference(id=e9b6b9ed-ef48-4986-9b86-2ef697578bf7), extensions={http://url=www.example.com})"));

}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ void whenDeserializingInteractionComponentThenDescriptionIsExpected() throws Exc
final InteractionComponent result = objectMapper.readValue(file, InteractionComponent.class);

// Then Description Is Expected
assertThat(result.getDescription().get(Locale.ENGLISH), is("value"));
assertThat(result.getDescription().get(Locale.US), is("value"));

}

Expand All @@ -86,7 +86,7 @@ void whenSerializingInteractionComponentThenResultIsEqualToExpectedJson() throws

.id("1")

.addDescription(Locale.ENGLISH, "value")
.addDescription(Locale.US, "value")

.build();

Expand All @@ -111,7 +111,7 @@ void whenCallingToStringThenResultIsExpected() throws IOException {
final String result = interactionComponent.toString();

// Then Result Is Expected
assertThat(result, is("InteractionComponent(id=1, description={en=value})"));
assertThat(result, is("InteractionComponent(id=1, description={en_US=value})"));

}

Expand All @@ -120,7 +120,7 @@ void whenBuildingInteractionComponentWithTwoDescriptionValuesThenDisplayLanguage

// When Building InteractionComponent With Two Description Values
final InteractionComponent interactionComponent = InteractionComponent.builder().id("1")
.addDescription(Locale.ENGLISH, "value").addDescription(Locale.GERMAN, "Wert").build();
.addDescription(Locale.US, "value").addDescription(Locale.GERMAN, "Wert").build();

// Then Description Language Map Has Two Entries
assertThat(interactionComponent.getDescription(), aMapWithSize(2));
Expand All @@ -131,7 +131,7 @@ void whenBuildingInteractionComponentWithTwoDescriptionValuesThenDisplayLanguage
void whenValidatingInteractionComponentWithAllRequiredPropertiesThenConstraintViolationsSizeIsZero() {

final InteractionComponent interactionComponent =
InteractionComponent.builder().id("1").addDescription(Locale.ENGLISH, "value").build();
InteractionComponent.builder().id("1").addDescription(Locale.US, "value").build();

// When Validating Interaction Component With All Required Properties
final Set<ConstraintViolation<InteractionComponent>> constraintViolations =
Expand All @@ -146,7 +146,7 @@ void whenValidatingInteractionComponentWithAllRequiredPropertiesThenConstraintVi
void whenValidatingInteractionComponentWithoutIdThenConstraintViolationsSizeIsOne() {

final InteractionComponent interactionComponent =
InteractionComponent.builder().addDescription(Locale.ENGLISH, "value").build();
InteractionComponent.builder().addDescription(Locale.US, "value").build();

// When Validating Interaction Component Without Id
final Set<ConstraintViolation<InteractionComponent>> constraintViolations =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ void givenFrenchAndEnglishKeyWhenGettingUSValueThenValueIsEnglish() throws Excep

// Given French And English Key
languageMap.put(Locale.FRENCH, "Couleur");
languageMap.put(Locale.ENGLISH, "Color");
languageMap.put(Locale.US, "Color");

// When Getting US Value
final String value = languageMap.get(LanguageRange.parse("en-US"));
Expand Down
Loading