In a simple test class like the one below:
#SpringBootTest
#Slf4j
#ActiveProfiles("test")
public class LocalizerTest {
#Autowired
AddressInfoLocalizer addressInfoLocalizer;
#Test
public void localizeIp() {
String ip = "8.8.8.8";
Optional<CityResponse> response = addressInfoLocalizer.localize(ip);
response.ifPresent(cityResponse -> log.info("{}", cityResponse));
}
}
With the AddressInfoLocalizer (sorry for the strange name but I had to make it up) being basically like this:
#Slf4j
#Component
public class AddressInfoLocalizer {
#Value("${geolocalization.dbpath}")
private String databasePath;
private DatabaseReader database;
#PostConstruct
public void initialize() {
log.info("GeoIP2 database path:{}", databasePath);
File database = new File(databasePath);
try {
this.database = new DatabaseReader.Builder(database).build();
} catch (IOException ioe) {
this.database = null;
log.warn("Problems encountered while initializing IP localization database, skipping resolutions");
}
}
public Optional<CityResponse> localize(String ipAddressString) {
if (isNull(database)) {
log.warn("Attempted to resolve an IP location with database problems, skipping.");
return Optional.empty();
}
try {
InetAddress ipAddress = InetAddress.getByName(ipAddressString);
return ofNullable(database.city(ipAddress));
} catch (UnknownHostException uhe) {
log.error("Unknown host {}, {}", ipAddressString, uhe.getCause());
return Optional.empty();
} catch (IOException ioe) {
log.error("IO error while opening database, {}", ioe.getCause().toString());
return Optional.empty();
} catch (GeoIp2Exception gip2e) {
log.error("GeoIP error, {}", gip2e.getCause().toString());
return Optional.empty();
}
}
}
I keep getting a NullPointerException when calling (in the test) addressInfoLocalizer.localize(ip);,
java.lang.NullPointerException
at com.bok.parent.LocalizerTest.localizeIp(LocalizerTest.java:26)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)
at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:221)
at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54)
while debugging I can actually see that the addressInfoLocalizer object is null.
I've created other classes the same way, but only this one seems to have that problem, what could be wrong?
What I found out is that not always the #SpringBootTest is enough, in some classes/cases (to be honest I don't have a 100% clear idea so I'm not gonna say stupidities) it is needed that you manually choose the test-runner, like below:
#SpringBootTest
#RunWith(SpringRunner.class)
public class FooTest {
...
}
Keep in mind that if you decide to instantiate a dependency by yourself then Spring won't be able to inject all the needed classes, and then you'd need to change the runner into something like #RunWith(MockitoJUnitRunner.class)
(credits to JUNIT Autowired instance is always null)
A better approach is to use spring's underlying mock beans.
#SpringBootTest(classes= AddressInfoLocalizer.class)
this is actually the new recommended way.
Two things here:
If you're testing, the ideal way is to mock instead of autowire(there can be exceptions)
You should use #ExtendWith(MockitoExtension.class) or #RunWith(MockitoJUnitRunner.class) so that your components will be loaded in spring context. However ExtendWith is preferred way to initialize beans/components. Because the later(RunWith) loads the entire spring context which might take more time
So, your code should look something like:
#Slf4j
#ActiveProfiles("test")
#ExtendWith(MockitoExtension.class)
public class LocalizerTest {
#Mock
AddressInfoLocalizer addressInfoLocalizer;
#Test
public void localizeIp() {
String ip = "8.8.8.8";
//Mock here.
Optional<CityResponse> response = addressInfoLocalizer.localize(ip);
response.ifPresent(cityResponse -> log.info("{}", cityResponse));
}
}
Reference/Read more:
https://www.baeldung.com/mockito-junit-5-extension
https://stackoverflow.com/questions/55276555/when-to-use-runwith-and-when-extendwith
https://www.javadoc.io/static/org.mockito/mockito-junit-jupiter/3.10.0/org/mockito/junit/jupiter/MockitoExtension.html
I am trying to write a unit test for class DataHandler.java this is in turn calling a parseDebeziumSchema method from SchemaParsor class.
This method converts a string to JSONArray, but when I am trying to mock it using when(schemaParsor.parseDebeziumSchema(json)).thenReturn(jsonArray); it is throwing java.lang.NoSuchMethodError: org.json.JSONArray.iterator()Ljava/util/Iterator exception.
The full stack trace is as follows, also I am attaching the DataHandler class, DataHandlerTest class and parseDebeziumSchema method codes as well:
java.lang.NoSuchMethodError: org.json.JSONArray.iterator()Ljava/util/Iterator;
at com.xoom.transformer.dbschemahandler.SchemaParsor.parseDebeziumSchema(SchemaParsor.java:43)
at com.xoom.transformer.utils.DataHandlerTest.testdataProcessor(DataHandlerTest.java:52)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.mockito.internal.runners.DefaultInternalRunner$1.run(DefaultInternalRunner.java:79)
at org.mockito.internal.runners.DefaultInternalRunner.run(DefaultInternalRunner.java:85)
at org.mockito.internal.runners.StrictRunner.run(StrictRunner.java:39)
at org.mockito.junit.MockitoJUnitRunner.run(MockitoJUnitRunner.java:163)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at com.intellij.rt.execution.application.AppMainV2.main(AppMainV2.java:131)
DataHandlerTest.java:
public class DataHandlerTest {
#Mock
private SchemaManager schemaManager;
#InjectMocks
private SchemaParsor schemaParsor;
#InjectMocks
private DataHandler dataHandler;
//Variables
private final String json = "{\"schema\":{\"type\":\"struct\",\"fields\":[{\"type\":\"struct\",\"fields\":[{\"type\":\"string\",\"optional\":false,\"field\":\"recipe_name\"}],\"optional\":true,\"name\":\"_0.0.0.160.Debezium_test.recipes.Value\",\"field\":\"before\"},{\"type\":\"struct\",\"fields\":[{\"type\":\"string\",\"optional\":false,\"field\":\"recipe_name\"}],\"optional\":true,\"name\":\"_0.0.0.160.Debezium_test.recipes.Value\",\"field\":\"after\"},{\"type\":\"struct\",\"fields\":[{\"type\":\"string\",\"optional\":true,\"field\":\"version\"},{\"type\":\"string\",\"optional\":false,\"field\":\"name\"},{\"type\":\"int64\",\"optional\":false,\"field\":\"server_id\"},{\"type\":\"int64\",\"optional\":false,\"field\":\"ts_sec\"},{\"type\":\"string\",\"optional\":true,\"field\":\"gtid\"},{\"type\":\"string\",\"optional\":false,\"field\":\"file\"},{\"type\":\"int64\",\"optional\":false,\"field\":\"pos\"},{\"type\":\"int32\",\"optional\":false,\"field\":\"row\"},{\"type\":\"boolean\",\"optional\":true,\"default\":false,\"field\":\"snapshot\"},{\"type\":\"int64\",\"optional\":true,\"field\":\"thread\"},{\"type\":\"string\",\"optional\":true,\"field\":\"db\"},{\"type\":\"string\",\"optional\":true,\"field\":\"table\"},{\"type\":\"string\",\"optional\":true,\"field\":\"query\"}],\"optional\":false,\"name\":\"io.debezium.connector.mysql.Source\",\"field\":\"source\"},{\"type\":\"string\",\"optional\":false,\"field\":\"op\"},{\"type\":\"int64\",\"optional\":true,\"field\":\"ts_ms\"}],\"optional\":false,\"name\":\"_0.0.0.160.Debezium_test.recipes.Envelope\"},\"payload\":{\"before\":null,\"after\":{\"recipe_name\":\"Chicken\"},\"source\":{\"version\":\"0.8.2\",\"name\":\"10.0.0.160\",\"server_id\":1,\"ts_sec\":1549019230,\"gtid\":null,\"file\":\"bin.000035\",\"pos\":263,\"row\":0,\"snapshot\":false,\"thread\":28,\"db\":\"Debezium_test\",\"table\":\"recipes\",\"query\":null},\"op\":\"c\",\"ts_ms\":1549019230377}}";
private final String topic_name = "database.table";
private final int partition = 1;
//Creating JSONObject
private Iterator iterator = null;
private JSONArray jsonArray=new JSONArray();
private JSONObject jsonObject=new JSONObject();
#Test //(expected=Exception.class)
public void testdataProcessor() throws JsonParseException, JSONException {
jsonObject.put("field","recipe_name");
jsonObject.put("type","string");
jsonArray.put(jsonObject);
dataHandler.dataProcessor(json, topic_name, partition);
when(schemaParsor.parseDebeziumSchema(json)).thenReturn(jsonArray);
verify(dataHandler, Mockito.times(1)).dataProcessor(json, topic_name, partition);
}
}
parseDebeziumSchema
public JSONArray parseDebeziumSchema(String json)throws JsonParseException{
debezium_schema_arrjson=new JSONArray();
try{
System.out.println("==========Raw Json===="+json);
JSONObject jsonObj=new JSONObject(json);
if(jsonObj.length()>0){
JSONObject schema_detail=jsonObj.getJSONObject("schema");
System.out.println("==========schema_detail===="+schema_detail);
JSONArray fields_json_arr=schema_detail.getJSONArray("fields");
System.out.println("==========fields_json_arr===="+fields_json_arr);
for(Object field_json_obj:fields_json_arr){
System.out.println("======field_json_obj===={}"+field_json_obj);
JSONObject jsonObject_field=jsonUtils.objectToJSONObject(field_json_obj);
JSONArray fields_json_arr_in=(JSONArray)jsonObject_field.get("fields");
for(Object j_obj:fields_json_arr_in){
debezium_schema_json=new JSONObject();
JSONObject jsonObject=jsonUtils.objectToJSONObject(j_obj);
debezium_schema_json.put("type",jsonObject.get("type"));
debezium_schema_json.put("field",jsonObject.get("field"));
debezium_schema_arrjson.put(debezium_schema_json);
}
break;
}
}
}
catch(Exception ex){
LOGGER.error("Cannot parse JSON for spring.application.json: "+json,ex);
throw new JsonParseException("SchemaParsor.parseDebeziumSchema. Debezium schema parse error.");
}
return debezium_schema_arrjson;
}
Any help will be highly appreciated.
There are two problems in your test:
Call stubbing must be configured before the actual interaction. So just swap these lines:
dataHandler.dataProcessor(json, topic_name, partition);
when(schemaParsor.parseDebeziumSchema(json)).thenReturn(jsonArray); //stub parseDebeziumSchema
Mockito.verify is for verification of interaction with a mock. But in your code, you are verifying a method call on the object under test. You don't see this error because your code breaks at point 1. Remove this line:
verify(dataHandler, Mockito.times(1)).dataProcessor(json, topic_name, partition);
To summarize, your code should look like the one below. I've also added verification that schemaParsor.parseDebeziumSchema(json) is called exactly once
#Test
public void testdataProcessor() throws JsonParseException, JSONException {
jsonObject.put("field","recipe_name");
jsonObject.put("type","string");
jsonArray.put(jsonObject);
when(schemaParsor.parseDebeziumSchema(json)).thenReturn(jsonArray); //stub parseDebeziumSchema
dataHandler.dataProcessor(json, topic_name, partition);
verify(schemaParsor, times(1)).parseDebeziumSchema(json); //verify that parseDebeziumSchema is called exactly once
}
I have a unit test I am writing for a class, and this class uses a ConfigurationManager I wrote to get configuration from a TOML object (and therefore from a TOML file).
The Code
Here is the relevant ConfigurationManager code:
public class ConfigurationManager {
// DEFAULT_LOGGING_LEVEL should represent level to use in production environment.
private final static Level DEFAULT_LOGGING_LEVEL = Level.FINE;
private final static String LOG_LEVEL_ENV_PROPERTY = "LOG_LEVEL";
private final static String TOML_FILE_NAME = "config.toml";
private final static String LOCAL_ENV_PROPERTY = "local";
private final static String ENV_PROPERTY = "MY_ENV";
private static Logger CM_LOGGER;
private Environment environment;
public ConfigurationManager() {
environment = new Environment();
CM_LOGGER = new LoggerUtil(ConfigurationManager.class.getName(), getLoggingLevel()).getLogger();
}
public File getTomlFile() throws URISyntaxException, FileNotFoundException {
URI uri = getConfigURI();
File tomlFile = new File(uri);
if (!tomlFile.exists()) {
String err = TOML_FILE_NAME + " does not exist!";
CM_LOGGER.severe(err);
throw new FileNotFoundException(err);
}
return tomlFile;
}
/**
* #return A URI representing the path to the config
* #throws URISyntaxException if getConfigURI encounters bad URI syntax.
*/
private URI getConfigURI() throws URISyntaxException {
return getClass().getClassLoader().getResource(TOML_FILE_NAME).toURI();
}
/**
* Method for getting the app configuration as a toml object.
*
* #return A toml object built from the config.toml file.
* #throws URISyntaxException if getConfigURI encounters bad URI syntax.
* #throws FileNotFoundException if getTomlFile can't find the config.toml file.
*/
public Toml getConfigToml() throws URISyntaxException, FileNotFoundException {
return new Toml().read(getTomlFile());
}
}
And here is the code that calls this Configuration Manager:
public class Listener {
// Initializations
private static final String CONFIG_LISTENER_THREADS = "listenerThreads";
private static final String DEFAULT_LISTENER_THREADS = "1";
/**
* Constructor for getting app properties and initializing executor service with thread pool based on app prop.
*/
#PostConstruct
void init() throws FileNotFoundException, URISyntaxException {
ConfigurationManager configurationManager = new ConfigurationManager();
int listenerThreads = Integer.parseInt(configurationManager.getConfigToml()
.getString(CONFIG_LISTENER_THREADS, DEFAULT_LISTENER_THREADS));
this.executorService = Executors.newFixedThreadPool(listenerThreads);
LOGGER.config("Listener executorService threads: " + listenerThreads);
}
...
}
And here is the test for that code (See comment to see where NPE is triggered):
public class ListenerTests {
#Mock
ConfigurationManager mockCM;
#InjectMocks
Listener listener = new Listener();
#Before
public void setUp(){
MockitoAnnotations.initMocks(this);
}
#Test
public void testListener_ShouldInit() throws FileNotFoundException, URISyntaxException {
when(mockCM.getConfigToml().getString(any(), any())).thenReturn("5"); // !!!NPE TRIGGERED BY THIS LINE!!!
listener.init();
verify(mockCM, times(1)).getConfigToml().getString(any(), any());
}
}
The Problem
I get a NullPointerException as follows
java.lang.NullPointerException
at com.bose.source_account_listener.ListenerTests.testListener_ShouldInit(ListenerTests.java:37)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
I have a guess as to the problem here but I'm not sure how to validate my guess. My guess is that I am mocking the ConfigurationManager, but the mock doesn't know that the ConfigurationManager can generate a TOML file which has a getString method, so I end up getting the NPE. This makes me think that I need a mock TOML for my mock ConfigurationManager, but I am neither certain this is the case or that this is the proper solution.
I am new to Mockito and Java in general so any help would be appreciated.
You need to mock every bit of your call, not just the full call. mockCM.getConfigToml() has no mock response, so it returns null, and a toString is invoked on a null object. Your options are to return a non-mocked "Toml" or mock a Toml and then set that up with a when configuration.
Toml tomlMock = Mockito.mock(Toml.class);
when(mockCM.getConfigToml()).thenReturn(tmolMock);
when(tmolMock.getString(any(), any())).thenReturn("5");
You're trying to mock the method of what is returned by calling getConfigToml. That is, you need to mock the object of what should be returned by getConfigToml, and then call getString on that object.
I am using OrientDB version 3.0.4
with Java and orientdb-client.3.0.4 Java driver/library.
I am trying to use EMBEDDEDLIST type as follows:
DB schema:
create class Phone EXTENDS V
create property Phone.number String
create class Profile EXTENDS V
create property Profile.name String
create property Profile.phone embeddedList Phone
Using OrientDB console, following works:
CREATE VERTEX Profile SET name = "User1", phone = [{ "number" : "914" }, { "number" : "212" }]
SELECT * From Profile where name="User1"
+----+------+-------+-----+-------------------------------------+
|# |#RID |#CLASS |name |phone |
+----+------+-------+-----+-------------------------------------+
|0 |#198:2|Profile|User1|[Phone{number:914},Phone{number:212}]|
+----+------+-------+-----+-------------------------------------+
Using Java It fails:
While trying to create the Profile Vertex having two Phone(s) objects stored as List (ArrayList), code fails with following exception:
com.orientechnologies.orient.core.exception.OValidationException: The field 'Profile.phone' has been declared as EMBEDDEDLIST but an incompatible type is used. Value: Phone{number:212}
DB name="test"
Error Code="4"
at com.orientechnologies.orient.core.record.impl.ODocument.validateEmbedded(ODocument.java:814)
Here is the code:
public void insertProfileTest() throws JsonProcessingException {
LOGGER.info(dbSession.getMetadata().getSchema().getClass(Profile.class).getProperty("name").toString());
LOGGER.info(dbSession.getMetadata().getSchema().getClass(Profile.class).getProperty("phone").toString());
LOGGER.info(dbSession.getMetadata().getSchema().getClass(Phone.class).getProperty("number").toString());
// Init
Profile userProfile = new Profile("Jane Doe");
Phone homePhone = new Phone("212");
Phone cellPhone = new Phone("718");
userProfile.addPhone(homePhone);
userProfile.addPhone(cellPhone);
final String json = MAPPER.writeValueAsString(userProfile);
LOGGER.info("Profile JSON:" + json);
LOGGER.info("Phone Class :" + userProfile.getPhone().getClass().getName());
// DB
final OVertex profileVertex = dbSession.newVertex("Profile");
profileVertex.setProperty("name", userProfile.getName());
profileVertex.setProperty("phone", userProfile.getPhone(), OType.EMBEDDEDLIST);
// Fails to Save -
// The field 'Profile.phone' has been declared as EMBEDDEDLIST but an incompatible type is used. Value: com.sample.profile.Phone#32f232a5
profileVertex.save();
}
Here is the output:
14:11:00.124 [main] INFO com.sample.profile.ProfileTest - Initializing begin
14:11:01.187 [main] INFO com.sample.profile.ProfileTest - OrientDB [remote:localhost/test] Status: [OPEN]
14:11:01.191 [main] INFO com.sample.profile.ProfileTest - name (type=STRING)
14:11:01.192 [main] INFO com.sample.profile.ProfileTest - phone (type=EMBEDDEDLIST)
14:11:01.192 [main] INFO com.sample.profile.ProfileTest - number (type=STRING)
14:11:01.233 [main] INFO com.sample.profile.ProfileTest - Profile JSON:{"name":"Jane Doe1","phone":[{"number":"212"},{"number":"718"}]}
14:11:01.234 [main] INFO com.sample.profile.ProfileTest - Phone Class :java.util.ArrayList
Jul 12, 2018 2:11:01 PM com.orientechnologies.common.log.OLogManager log
INFO: Orient Engine is shutting down...
com.orientechnologies.orient.core.exception.OValidationException: The field 'Profile.phone' has been declared as EMBEDDEDLIST but an incompatible type is used. Value: Phone{number:212}
DB name="test"
Error Code="4"
at com.orientechnologies.orient.core.record.impl.ODocument.validateEmbedded(ODocument.java:814)
at com.orientechnologies.orient.core.record.impl.ODocument.validateField(ODocument.java:601)
at com.orientechnologies.orient.core.record.impl.ODocument.validate(ODocument.java:2365)
at com.orientechnologies.orient.core.db.document.ODatabaseDocumentAbstract.saveInternal(ODatabaseDocumentAbstract.java:2057)
at com.orientechnologies.orient.core.db.document.ODatabaseDocumentAbstract.save(ODatabaseDocumentAbstract.java:2042)
at com.orientechnologies.orient.core.db.document.ODatabaseDocumentAbstract.save(ODatabaseDocumentAbstract.java:84)
at com.orientechnologies.orient.core.record.impl.ODocument.save(ODocument.java:2109)
at com.orientechnologies.orient.core.record.impl.ODocument.save(ODocument.java:2100)
at com.orientechnologies.orient.core.record.impl.ODocument.save(ODocument.java:63)
at com.sample.profile.ProfileTest.insertProfileTest(ProfileTest.java:98)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
Here are the Java classes:
package com.sample.profile;
public class Phone {
private String number;
public Phone() {
}
public Phone(String number) {
this.number = number;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
#Override
public String toString() {
return "Phone{" +
"number:" + number +
'}';
}
}
package com.sample.profile;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
public class Profile {
private String name;
private Collection phone;
public Profile() {
}
public Profile(String name) {
this.name = name;
}
public Profile(String name, Collection phone) {
this.name = name;
this.phone = phone;
}
public void addPhone(Phone phoneNumber)
{
if (this.phone == null) {
this.phone = new ArrayList();
}
this.phone.add(phoneNumber);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Collection getPhone() {
return phone;
}
public void setPhone(Collection phone) {
this.phone = phone;
}
#Override
public String toString() {
return "Profile{" +
"name='" + name + '\'' +
", phone=" + Arrays.toString(phone.toArray()) +
'}';
}
}
Solution:
I resolved the issue as follows:
public void insertProfileTest() throws JsonProcessingException {
LOGGER.info(dbSession.getMetadata().getSchema().getClass(Profile.class).getProperty("name").toString());
LOGGER.info(dbSession.getMetadata().getSchema().getClass(Profile.class).getProperty("phone").toString());
LOGGER.info(dbSession.getMetadata().getSchema().getClass(Phone.class).getProperty("number").toString());
// Init
Profile userProfile = new Profile("Jane Doe");
Phone homePhone = new Phone("212");
Phone cellPhone = new Phone("718");
userProfile.addPhone(homePhone);
userProfile.addPhone(cellPhone);
final String json = MAPPER.writeValueAsString(userProfile);
LOGGER.info("Profile JSON:" + json);
LOGGER.info("Phone Class :" + userProfile.getPhone().getClass().getName());
// DB
List phoneVertexList = new ArrayList();
for (Phone phone: userProfile.getPhone()) {
final OVertex phoneVertex = dbSession.newVertex("Phone");
phoneVertex.setProperty("number", phone.getNumber());
phoneVertexList.add(phoneVertex);
}
final OVertex profileVertex = dbSession.newVertex("Profile");
profileVertex.setProperty("name", userProfile.getName());
profileVertex.setProperty("phone", phoneVertexList, OType.EMBEDDEDLIST);
profileVertex.save();
}
What is not clear to me as per the documentation at
https://orientdb.com/docs/last/general/Types.html for the EMBEDDEDLIST
that it should be of Java type List<Object> but I had to use List<OVertex> .
The documentation states "The Records are contained inside the owner. The contained records have no Record ID's and are reachable only by navigating the owner record" but then in this case Phone vertexes were created as follows:
select * from Profile
+----+-----+-------+--------+-------------------------------------+
|# |#RID |#CLASS |name |phone |
+----+-----+-------+--------+-------------------------------------+
|0 |#41:0|Profile|Jane Doe|[Phone{number:212},Phone{number:718}]|
+----+-----+-------+--------+-------------------------------------+
select * from Phone
+----+-----+------+------+
|# |#RID |#CLASS|number|
+----+-----+------+------+
|0 |#33:0|Phone |212 |
|1 |#34:0|Phone |718 |
+----+-----+------+------+
The documentation at following locations seems very minimal and do not provide example of EMBEDDEDLIST.
https://orientdb.com/docs/last/java/Java-Query-API.html
https://tinkerpop.apache.org/docs/current/reference/#connecting-via-java
I am wondering if anyone can point to better documentation for use of Java API to interact with OrientDB or any GraphDB.
I´m developing an Eclipse 4 RCP Application and I want to test some functions of my Parts.
I have a Test Class like this:
#BeforeClass
public static void initUI() {
display = new Display();
shell = new Shell(display);
configPart = new ConfigPart();
configPart.postConstruct(shell);
}
#Test
public void testConfigPart() {
String testText = "TitleText";
configPart.title.setText(testText);
assertEquals(testText, ConfigHandler.getInstance().getInternalConfig()
.getTitle());
}
During the creation of the ConfigPart a DataBinding is created and that is where I run into an AssertionFailedException. The statement is:
DataBindingContext ctx = new DataBindingContext();
Is there a way to avoid this or is there another way to test E4 Applications?
Edit:
The statement(s) where the Exception is raised:
public DataBindingContext(Realm validationRealm) {
Assert.isNotNull(validationRealm, "Validation realm cannot be null");
public static void isNotNull(Object object, String message) {
if (object == null) throw new AssertionFailedException("null argument:" + message);
The Stack Trace:
org.eclipse.core.runtime.AssertionFailedException: null argument:Validation realm cannot be null
at org.eclipse.core.runtime.Assert.isNotNull(Assert.java:85)
at org.eclipse.core.databinding.DataBindingContext.<init>(DataBindingContext.java:95)
at org.eclipse.core.databinding.DataBindingContext.<init>(DataBindingContext.java:82)
at de.uni_due.s3.jack.editor.parts.config.ConfigPart.addDataBinding(ConfigPart.java:350)
at de.uni_due.s3.jack.editor.parts.config.ConfigPart.postConstruct(ConfigPart.java:81)
at de.uni_due.s3.jack.editor.parts.config.ConfigPartTest.initUI(ConfigPartTest.java:28)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
A call to the empty constructor new DataBindingContext() delegates to this(Realm.getDefault()) (see Eclipse source code). This means that you need to have some kind of a stub Realm set as default for your testing purposes.
You can use this solution from the Eclipse Wiki. Here is a copy-paste from the Wiki (adapted for your setup). I would think about whether you really need to have the setup in #BeforeClass or if #Before would be better.
public class DefaultRealm extends Realm {
private Realm previousRealm;
public DefaultRealm() {
previousRealm = super.setDefault(this);
}
/**
* #return always returns true
*/
public boolean isCurrent() {
return true;
}
protected void syncExec(Runnable runnable) {
runnable.run();
}
/**
* #throws UnsupportedOperationException
*/
public void asyncExec(Runnable runnable) {
throw new UnsupportedOperationException("asyncExec is unsupported");
}
/**
* Removes the realm from being the current and sets the previous realm to the default.
*/
public void dispose() {
if (getDefault() == this) {
setDefault(previousRealm);
}
}
}
Test code:
private static DefaultRealm realm;
#BeforeClass
public static void initUI() {
display = new Display();
shell = new Shell(display);
realm = new DefaultRealm();
configPart = new ConfigPart();
configPart.postConstruct(shell);
}
#AfterClass
public static void tearDownUI() {
realm.dispose();
}