Citrus TestNG test Data Provider Mismatch - citrus-framework

I get an exception - data provider mismatch when trying to get citrus context with a data provider
This is the test and the data provider
#DataProvider(name = "todoDataProvider")
public Object[][] todoDataProvider() {
return new Object[][] {
new String[] {"todo1", "Description: todo1"},
new String[] {"todo2", "Description: todo2"},
new String[] {"todo3", "Description: todo3"}
};
}
#Test(dataProvider = "todoDataProvider")
#CitrusTest
#Parameters({"name", "description", "context"})
public void testProvider(
String name, String description, #CitrusResource #Optional TestContext context) {
variable("todoId", "citrus:randomUUID()");
// this.name(todoName);
echo(name);
}
org.testng.internal.reflect.MethodMatcherException:
Data provider mismatch
Method: testProvider([Parameter{index=0, type=java.lang.String, declaredAnnotations=[]}, Parameter{index=1, type=java.lang.String, declaredAnnotations=[]}, Parameter{index=2, type=com.consol.citrus.context.TestContext, declaredAnnotations=[#com.consol.citrus.annotations.CitrusResource(), #org.testng.annotations.Optional(value=null)]}])
Arguments: [(java.lang.String)todo1,(java.lang.String)Description: todo1]
at org.testng.internal.reflect.DataProviderMethodMatcher.getConformingArguments(DataProviderMethodMatcher.java:49)
at org.testng.internal.Invoker.injectParameters(Invoker.java:1293)
at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:1187)
at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:126)
at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:109)
at org.testng.TestRunner.privateRun(TestRunner.java:744)
at org.testng.TestRunner.run(TestRunner.java:602)
at org.testng.SuiteRunner.runTest(SuiteRunner.java:380)
at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:375)
at org.testng.SuiteRunner.privateRun(SuiteRunner.java:340)
at org.testng.SuiteRunner.run(SuiteRunner.java:289)
at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)
at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:86)
at org.testng.TestNG.runSuitesSequentially(TestNG.java:1301)
at org.testng.TestNG.runSuitesLocally(TestNG.java:1226)
at org.testng.TestNG.runSuites(TestNG.java:1144)
at org.testng.TestNG.run(TestNG.java:1115)
at org.testng.remote.AbstractRemoteTestNG.run(AbstractRemoteTestNG.java:114)
at org.testng.remote.RemoteTestNG.initAndRun(RemoteTestNG.java:251)
at org.testng.remote.RemoteTestNG.main(RemoteTestNG.java:77)

The citrus parameters seem to get injected into the data provider parameters that are passed, so the data provider needs to include space for the citrus parameters.
found
https://github.com/citrusframework/citrus/commit/952204eaacf672677a01cc66f3385f64cd08f8d4
which had a fix for passing citrus variables with data provider, but more importantly/useful to me, unit tests. So played with unit tests and looks like the null is required in the data provider for each citrus variable to be injected/passed.
#DataProvider(name = "todoDataProvider")
public Object[][] todoDataProvider() {
return new Object[][] {
new String[] {"todo1", "Description: todo1", null},
new String[] {"todo2", "Description: todo2", null},
new String[] {"todo3", "Description: todo3", null}
};
}
#Test(dataProvider = "todoDataProvider")
#CitrusTest
#Parameters({"name", "description", "context"})
public void testProvider(
String name, String description, #CitrusResource #Optional TestContext context) {
variable("todoId", "citrus:randomUUID()");
// this.name(todoName);
echo(name);
}
#Test(dataProvider = "testData")
#Parameters({"data", "temp", "runner", "context"})
#CitrusTest
public void injectResourceRunnerCombinedWithParameter(
String data,
String test,
#CitrusResource TestRunner testRunner,
#CitrusResource TestContext context) {
final String number = Functions.randomNumber(10L, context);
context.setVariable("message", "Injection worked!");
testRunner.echo("${message}");
testRunner.echo("${data}");
testRunner.createVariable("random", number);
testRunner.run(
new AbstractTestAction() {
#Override
public void doExecute(TestContext context) {
Assert.assertEquals(context.getVariable("random"), number);
}
});
}
#DataProvider
public Object[][] testData() {
return new Object[][] {{"hello", "test", null, null}, {"bye", "test", null, null}};
}

Related

How to use #BeforeStep Job Parameters in JdbcCursorItemReader for named Query

I have the code like below
#Bean
public JdbcCursorItemReader<Map<String, Object>> itemReader() {
return new JdbcCursorItemReader<Map<String, Object>>() {
private JobParameters jobParameter;
String sql = "select EMPLOYEE_ID as empId, EMPLOYEE_NAME as empName EMPLOYEE_AGE as age from EMPLOYEE EMPLOYEE_DEPT =:empDept and EMPLOYEE_SAL > :empSal";
Map<String, Object> namedParameters = null;
#PostConstruct
public void initialize() throws Exception
{
setDataSource(dataSource);
setSql("select 1 from dual");
setRowMapper(new ColumnMapRowMapper());
}
#BeforeStep
public void retrieveExecutionContext(StepExecution stepExecution)
{
jobParameter = stepExecution.getJobParameters();
namedParameters = new HashMap<String, Object>() {
{
put("bstd", jobParameter.getString("empDept"));
put("bwtn", jobParameter.getString("empSal"));
}
};
jobParameter.getParameters().forEach((k, v) -> System.out.println("key =" + k + ", Value:" + v));
}
#Override
public void afterPropertiesSet() throws Exception {
setSql(NamedParameterUtils.substituteNamedParameters(sql, new MapSqlParameterSource(namedParameters)));
setPreparedStatementSetter(new ListPreparedStatementSetter(
Arrays.asList(NamedParameterUtils.buildValueArray(sql, namedParameters))));
setRowMapper(new ColumnMapRowMapper());
setDataSource(dataSource);
super.afterPropertiesSet();
}
};
}
Tried using calling afterPropertiesSet, but still seeing below exception
Caused by: org.springframework.dao.InvalidDataAccessApiUsageException: No value supplied for the SQL parameter 'empDept': No value registered for key 'empDept'
at org.springframework.jdbc.core.namedparam.NamedParameterUtils.buildValueArray(NamedParameterUtils.java:361) ~[spring-jdbc-5.3.22.jar:5.3.22]
at org.springframework.jdbc.core.namedparam.NamedParameterUtils.buildValueArray(NamedParameterUtils.java:485) ~[spring-jdbc-5.3.22.jar:5.3.22]
Requirement is dynamic query, so don't have control of the Select query and the where conditions.
Thanks in advance,
You can use a SpEL expression to inject and use job parameters in your item reader bean definition as follows:
#Bean
#StepScope
public JdbcCursorItemReader<Map<String, Object>> itemReader(#Value("#{jobParameters['empDept']}") String empDept, #Value("#{jobParameters['empSal']}") String empSal) {
JdbcCursorItemReader<Map<String, Object>> itemReader = new JdbcCursorItemReader<>();
// use parameters 'empDept' and 'empSal' in your sql query as needed
return itemReader;
}
Note that the item reader should be step-scoped for that to work. For more details, please refer to the documentation: Late Binding of Job and Step Attributes.

Is there any REST API to fetch all rules from Repository in Drools

As you can see, all rules can be listed in project explorer, i am wondering Drools workbench has such a Rest API for this, but I went through online document document, there is no such API. any suggestion on this? thanks in advance.
https://docs.jboss.org/drools/release/latest/drools-docs/html/ch20.html#d0e22619
Best Regards
Yuhua
As far as I know, there is no REST API to do that (public at least). One option do you have though is to use git to get that information from the workbench.
The storage of the workbench is based on git. Each repository in the workbench is actually a git repository. The workbench allows you to clone those repositories and to do whatever you need with them just as with any other git repo out there.
Inside each of the git repositories you will find zero or more maven projects. Indeed, each of the projects you see in the workbench is a real maven project. The different assets in your projects (drl rules, guided rules, decision table, etc.) will be available under the resources directory of the corresponding project.
Hope it helps,
As Esteban Aliverti mentioned, there is no ready to use API to achieve this. However, we can write a custom extension to KIE Server to fetch all the rules deployed.
It is explained in detailed here.
I have similar use case in my application and did the following implementation for fetching rules.
CusomtDroolsKieServerApplicationComponentsService
public class CusomtDroolsKieServerApplicationComponentsService implements KieServerApplicationComponentsService {
private static final String OWNER_EXTENSION = "Drools";
public Collection<Object> getAppComponents(String extension, SupportedTransports type, Object... services) {
// skip calls from other than owning extension
if (!OWNER_EXTENSION.equals(extension)) {
return Collections.emptyList();
}
RulesExecutionService rulesExecutionService = null;
KieServerRegistry context = null;
for (Object object : services) {
if (RulesExecutionService.class.isAssignableFrom(object.getClass())) {
rulesExecutionService = (RulesExecutionService) object;
continue;
} else if (KieServerRegistry.class.isAssignableFrom(object.getClass())) {
context = (KieServerRegistry) object;
continue;
}
}
List<Object> components = new ArrayList<Object>(1);
if (SupportedTransports.REST.equals(type)) {
components.add(new RuleRESTService(rulesExecutionService, context));
}
return components;
}
RuleRestService
#Path("server/containers/instances/{id}/ksession")
public class RuleRESTService {
private RulesExecutionService rulesExecutionService;
private KieServerRegistry registry;
public RuleRESTService() {
}
public RuleRESTService(RulesExecutionService rulesExecutionService, KieServerRegistry registry) {
this.rulesExecutionService = rulesExecutionService;
this.registry = registry;
}
public RulesExecutionService getRulesExecutionService() {
return rulesExecutionService;
}
public void setRulesExecutionService(RulesExecutionService rulesExecutionService) {
this.rulesExecutionService = rulesExecutionService;
}
public KieServerRegistry getRegistry() {
return registry;
}
public void setRegistry(KieServerRegistry registry) {
this.registry = registry;
}
#POST
#Path("/{ksessionId}")
#Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
#Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public Response fetchAllRules(#Context HttpHeaders headers, #PathParam("id") String id,
#PathParam("ksessionId") String ksessionId, String cmdPayload) {
Variant v = getVariant(headers);
try {
System.out.println("CREATING KieContainerInstance ");
KieContainerInstance kci = registry.getContainer(id);
String contentType = getContentType(headers);
MarshallingFormat format = MarshallingFormat.fromType(contentType);
if (format == null) {
format = MarshallingFormat.valueOf(contentType);
}
Marshaller marshaller = kci.getMarshaller(format);
RuleAccessor accessor = new RuleAccessor();
List<RuleData> rules = accessor.fetchAllRules(kci.getKieContainer());
String result = marshaller.marshall(rules);
return createResponse(result, v, Response.Status.OK);
} catch (Exception ex) {
ex.printStackTrace();
String response = "Execution failed with error : " + ex.getMessage();
System.out.println("Returning Failure response with content '{}' :" + response);
return createResponse(response, v, Response.Status.INTERNAL_SERVER_ERROR);
}
}
RuleAccessor
public class RuleAccessor {
public List<RuleData> fetchAllRules(KieContainer kContainer) {
kContainer.getKieBaseNames().stream()
.forEach(kieBase -> rules.addAll(fetchRules(kContainer1.getKieBase(kieBase))));
return rules;
}
public List<RuleData> fetchRules(KieBase kieBase) {
List<RuleData> ruleData = new ArrayList<>();
for (KiePackage kp : kieBase.getKiePackages()) {
RuleData data = new RuleData();
for (Rule r1 : kp.getRules()) {
RuleImpl r = (RuleImpl) r1;
data.agendaGroup(r.getAgendaGroup()).packageId(r.getPackageName()).ruleName(r.getName())
.enabled(Boolean.getBoolean((((EnabledBoolean) r.getEnabled()).toString())))
.effectiveDate(String.valueOf(r.getDateEffective()))
.dateExpires(String.valueOf(r.getDateExpires())).dialect(r.getDialect())
.salience(r.getSalienceValue()).metaData(r.getMetaData());
try {
Resource resource = r.getResource();
Reader reader = resource.getReader();
BufferedReader bufferedReader = new BufferedReader(reader);
String line = null;
StringBuilder builder = new StringBuilder();
while ((line = bufferedReader.readLine()) != null) {
builder.append(line);
}
data.ruleContent(builder.toString());
ruleData.add(data);
} catch (IOException e) {
e.printStackTrace();
}
}
}
return ruleData;
}
public static class RuleData {
private String packageId;
private String ruleName;
private String type;
private String agendaGroup;
private String ruleContent;
private boolean isEnabled;
private String effectiveDate;
private String dateExpires;
private String dialect;
private int salience;
private Map<String, Object> metaData;
public boolean isEnabled() {
return isEnabled;
}
public RuleData enabled(boolean isEnabled) {
this.isEnabled = isEnabled;
return this;
}
public String effectiveDate() {
return effectiveDate;
}
public RuleData effectiveDate(String effectiveDate) {
this.effectiveDate = effectiveDate;
return this;
}
public String getDateExpires() {
return dateExpires;
}
public RuleData dateExpires(String dateExpires) {
this.dateExpires = dateExpires;
return this;
}
public String getDialect() {
return dialect;
}
public RuleData dialect(String dialect) {
this.dialect = dialect;
return this;
}
public int getSalience() {
return salience;
}
public RuleData salience(int salience) {
this.salience = salience;
return this;
}
public Map<String, Object> getMetaData() {
return metaData;
}
public RuleData metaData(Map<String, Object> metaData) {
this.metaData = metaData;
return this;
}
public String getRuleContent() {
return ruleContent;
}
public RuleData ruleContent(String ruleContent) {
this.ruleContent = ruleContent;
return this;
}
public String getPackageId() {
return packageId;
}
public RuleData packageId(String packageId) {
this.packageId = packageId;
return this;
}
public String getRuleName() {
return ruleName;
}
public RuleData ruleName(String ruleName) {
this.ruleName = ruleName;
return this;
}
public String getType() {
return type;
}
public RuleData type(String type) {
this.type = type;
return this;
}
public String getAgendaGroup() {
return agendaGroup;
}
public RuleData agendaGroup(String agendaGroup) {
this.agendaGroup = agendaGroup;
return this;
}
}
}
You can make a REST call to Kie Server from you application to access all the rules available for the given container.
http://localhost:8080/kie-server/services/rest/server/containers/instances/<container-id>/ksession/<session-id>

Retrofit 2.0-beta-2 is adding literal quotes to MultiPart values

Went to upgrade to Retrofit 2.0 and running into this weird problem.
I have a method to log a user in
public interface ApiInterface {
#Multipart
#POST("user/login/")
Call<SessionToken> userLogin(#Part("username") String username, #Part("password") String password);
}
When I look at the key value POST params on the server side they print like this
username : "brian"
password : "password"
The same method using retrofit 1.9 the K:V pairs look like
username : brian
password : password
It's adding literal quotes to the POST variables
If I use any other rest client the variables print like the second way without the quotes.
Here is how I build the Retrofit instance with an interceptor
OkHttpClient client = new OkHttpClient();
client.interceptors().add(new Interceptor() {
#Override
public Response intercept(Chain chain) throws IOException {
Request original = chain.request();
// Customize the request
Request request = original.newBuilder()
.header("Accept", "application/json")
.header("Authorization", myPrefs.accessToken().getOr(""))
.method(original.method(), original.body())
.build();
Response response = chain.proceed(request);
// Customize or return the response
return response;
}
});
Ok2Curl.set(client);
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(apiEndpoint)
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build();
I imagine i'm doing something wrong with the converter but not sure what.
Has anyone else ran into this problem yet? I know its in beta but it's pretty widly used.
This is because it's running through the JSON converter.
Solution1:
use RequestBody instead of String
public interface ApiInterface {
#Multipart
#POST("user/login/")
Call<SessionToken> userLogin(#Part("username") RequestBody username, #Part("password") RequestBody password);
}
Build RequestBody:
RequestBody usernameBody = RequestBody.create(MediaType.parse("text/plain"), usernameStr);
RequestBody passwordBody = RequestBody.create(MediaType.parse("text/plain"), passwordStr);
Launch network operation:
retrofit.create(ApiInterface.class).userLogin(usernameBody , passwordBody).enqueue()....
Solution2: Create a custom ConverterFactory to dispose String part value.
For: Retrofit2 final release not beta. (com.squareup.retrofit2:retrofit:2.0.0)
Create your StringConverterFactory:
public class StringConverterFactory extends Converter.Factory {
private static final MediaType MEDIA_TYPE = MediaType.parse("text/plain");
public static StringConverterFactory create() {
return new StringConverterFactory();
}
#Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
if (String.class.equals(type)) {
return new Converter<ResponseBody, String>() {
#Override
public String convert(ResponseBody value) throws IOException {
return value.string();
}
};
}
return null;
}
#Override
public Converter<?, RequestBody> requestBodyConverter(Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
if(String.class.equals(type)) {
return new Converter<String, RequestBody>() {
#Override
public RequestBody convert(String value) throws IOException {
return RequestBody.create(MEDIA_TYPE, value);
}
};
}
return null;
}
}
Add to your retrofit instance:
retrofit = new Retrofit.Builder()
.baseUrl(SERVER_URL)
.client(client)
.addConverterFactory(StringConverterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();
Attention: StringConverterFactory should add before GsonConverterFactory!
then you can use String as part value directly.
You can find more information about this issue in https://github.com/square/retrofit/issues/1210
I have the same problem, and how it solved:
1) Add to build.gradle:
compile 'com.squareup.retrofit2:converter-scalars:2.1.0' // Remember to add the same version
2) Add one line here:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(URL_BASE)
.addConverterFactory(ScalarsConverterFactory.create()) // this line
.addConverterFactory(GsonConverterFactory.create(gson))
.client(getUnsafeOkHttpClient())
.build();
What about to do in that way?
RequestBody caption = RequestBody.create(MediaType.parse("text/plain"), new String("caption"));
Here is how to resolve it,
Firstly:
return new Retrofit.Builder()
.baseUrl(Env.GetApiBaseUrl())
.addConverterFactory(new GsonStringConverterFactory())
.addConverterFactory(GsonConverterFactory.create(gson))
.client(getHttpClient())
.build();
Create a CustomConverter like this one, this is needed by Retrofit 2, unless some fix the "feature" added in v2.
public class GsonStringConverterFactory extends Converter.Factory {
private static final MediaType MEDIA_TYPE = MediaType.parse("text/plain");
#Override
public Converter<?, RequestBody> toRequestBody(Type type, Annotation[] annotations) {
if (String.class.equals(type))// || (type instanceof Class && ((Class<?>) type).isEnum()))
{
return new Converter<String, RequestBody>() {
#Override
public RequestBody convert(String value) throws IOException {
return RequestBody.create(MEDIA_TYPE, value);
}
};
}
return null;
}
}
I've found another one solution except those. Worked with Retrofit 2.1.0. (Rx adapter is optional here)
My retrofit interface looks like this:
#POST("/children/add")
Observable<Child> addChild(#Body RequestBody requestBody);
And in ApiManager I use it like this:
#Override
public Observable<Child> addChild(String firstName, String lastName, Long birthDate, #Nullable File passportPicture) {
MultipartBody.Builder builder = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("first_name", firstName)
.addFormDataPart("last_name", lastName)
.addFormDataPart("birth_date", birthDate + "");
//some nullable optional parameter
if (passportPicture != null) {
builder.addFormDataPart("certificate", passportPicture.getName(), RequestBody.create(MediaType.parse("image/*"), passportPicture));
}
return api.addChild(builder.build());
}
It is similar to Solution1 from Loyea but I think that it's little a bit more elegant.
If your UI is showing your responses with quotes, you can use getAsString instead of toString
I don't know if it is too late, but we can also send requests with RequestBody.
Example:
public interface ApiInterface {
#Multipart
#POST("user/login/")
Call<SessionToken> userLogin(#Part("username") String username, #Part("password") String password);
}
We can convert as below:
public interface ApiInterface {
#Multipart
#POST("user/login/")
Call<SessionToken> userLogin(#Part("username") RequestBody username, #Part("password") String password);
}

GWT Mockito Test in Column

This is my Java code. I would like to create a test with mockito for update element. Can you help me for this?
public EditURLComposite(
CommandFacade commandFacade,
String testID,
EventBus eventBus) {
super(false, true);
this.eventBus = eventBus;
this.commandFacade = commandFacade;
uiBinder.createAndBindUi(this);
eventBinder.bindEventHandlers(this, eventBus);
if (getElement() != null) {
getElement().setId(testID);
url.getElement().setId(testID + "_url");
addButton.getElement().setId("resetButton");
}
dataProvider.addDataDisplay(table);
// Description
TextColumn<String> urlColumn = new TextColumn<String>() {
#Override
public String getValue(
String search) {
return search;
}
};
Column<String, String> deleteColumn = new Column<String, String>(new CellButton(messages.delete())) {
#Override
public String getValue(
final String url) {
return "Delete";
}
};
deleteColumn.setFieldUpdater(new FieldUpdater<String, String>() {
#Override
public void update(
final int index,
String url,
String value) {
boolean confirm = Window.confirm("Do you want to delete the URL '" + url + "' ?");
if (confirm == true) {
EditURLComposite.this.commandFacade.performCommand(
new DeleteIntegrationURLServerCommand(user.getUsername(), url),
DeleteIntegrationURLClientCommand.getType(),
deleteURLEventHandler);
}
}
});
ResizableTextHeader.addColumn(table, urlColumn, "URL");
ResizableTextHeader.addColumn(table, deleteColumn, "Delete");
table.setColumnWidth(urlColumn, "150px");
table.setWidth("200px");
}
I've found a solution for this problem. There is new code.
deleteColumn.setFieldUpdater(new FieldUpdater<String, String>() {
#Override
public void update(
final int index,
String url,
String value) {
boolean confirm = Window.confirm("Do you want to delete the URL '" + url + "' ?");
updateDeleteColumn(url, confirm);
}
}
void updateDeleteColumn(
String url,
Boolean confirm) {
if (confirm == true) {
EditURLComposite.this.commandFacade.performCommand(
new DeleteIntegrationURLServerCommand(user.getUsername(), url),
DeleteIntegrationURLClientCommand.getType(),
deleteURLEventHandler);
}
}
and finally test:
#SuppressWarnings({"unchecked", "static-access"})
#Test
public void testUpdateDeleteColumn() {
// Setup`enter code here`
String url = "http://blahblah.com";
UserRPC user = mockupUser();
composite.user = user;
// Test
composite.updateDeleteColumn(url, true);
// Checks
Mockito.verify(commandFacade).performCommand(
Mockito.any(DeleteIntegrationURLServerCommand.class),
Mockito.any(Type.class),
Mockito.any(DeleteIntegrationURLEventHandler.class));
}

spring data mongodb converter

I am using spring data mongo-db 1.4.1.RELEASE.
My entity 'Event' has a getter method which is calculated based on other properties:
public int getStatus() {
return (getMainEventId() == null) ? (elapseTimeInMin() < MINIMUM_TIME ? CANDIDATE :
VALID) : POINTER;
}
I wanted the property 'status' to be persisted only through the getter ,so I wrote converters:
#WritingConverter
public class EventWriteConverter implements Converter<Event ,BasicDBObject > {
static final Logger logger = LoggerFactory.getLogger(EventWriteConverter.class.getCanonicalName());
public BasicDBObject convert(Event event) {
logger.info("converting " +event );
if (event.getMainEventId() != null)
return new BasicDBObject("mainEventId", event.getMainEventId() );
BasicDBObject doc = new BasicDBObject("status",event.getStatus()).
append("updated_date",new Date()).
append("start",event.getS0()).
append("end",event.getS1()).
append("location",event.getLocation()).
;
BasicDBList list = new BasicDBList();
doc.append("access_points",event.getHotPoints());
return doc;
}
#ReadingConverter
public class EventReadConverter implements Converter<BasicDBObject, Event> {
#Inject
HotPointRepositry hotRepositry;
static final Logger logger = LoggerFactory.getLogger(EventReadConverter.class.getCanonicalName());
public Event convert(BasicDBObject doc) {
logger.info(" converting ");
Event event = new Event();
event.setId(doc.getObjectId("_id"));
event.setS0(doc.getDate("start"));
event.setS1(doc.getDate("end"));
BasicDBList dblist = (BasicDBList) doc.get("hot_points");
if (dblist != null) {
for (Object obj : dblist) {
ObjectId hotspotId = ((BasicDBObject) obj).getObjectId("_id");
event.addHot(hotRepositry.findOne(hotId));
}
}
dblist = (BasicDBList) doc.get("devices");
if (dblist != null) {
for (Object obj : dblist)
event.addDevice(obj.toString());
}
event.setMainEventId(doc.getObjectId("mainEventId"));
return event;
}
}
My test mongo configuration is
#Profile("test")
#Configuration
#EnableMongoRepositories(basePackages = "com.echo.spring.data.mongo")
#ComponentScan(basePackages = "com.echo.spring.data.mongo" )
public class MongoDbTestConfig extends AbstractMongoConfiguration {
static final Logger logger = LoggerFactory.getLogger(MongoDbTestConfig.class.getCanonicalName());
#Override
protected String getDatabaseName() {
return "echo";
}
#Override
public Mongo mongo() {
return new Fongo("echo-test").getMongo();
}
#Override
protected String getMappingBasePackage() {
return "com.echo.spring.data.mongo";
}
#Bean
#Override
public CustomConversions customConversions() {
logger.info("loading custom converters");
List<Converter<?, ?>> converterList = new ArrayList<Converter<?, ?>>();
converterList.add(new EventReadConverter());
converterList.add(new EventWriteConverter());
CustomConversions cus = new CustomConversions(converterList);
return new CustomConversions(converterList);
}
}
And my test (using fongo) is
ActiveProfiles("test")
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = MongoDbTestConfig.class )
public class SampleMongoApplicationTests {
#Test
#ShouldMatchDataSet(location = "/MongoJsonData/events.json")
public void shouldSaveEvent() throws IOException {
URL url = Resources.getResource("MongoJsonData/events.json");
List<String> lines = Resources.readLines(url,Charsets.UTF_8);
for (String line : lines) {
Event event = objectMapper.readValue(line.getBytes(),Event.class);
eventRepository.save(event);
}
}
I can see the converters are loaded when the configuration customConversions() is called
I added logging and breakpoints in the convert methods but they do not seems to be
called when I run or debug, though they are loaded .
What am I doing wrong ?
I had a similar situation, I followed Spring -Mongodb storing/retrieving enums as int not string
and I need both the converter AND converterFactory wired to get it working.