I'm trying to convert a List<String[]> into List<Object> using Dozer but unable to map the index values to the property fields using mapper API configuration.
How can I map the members of the String[] into individual object fields with each index targeting a specific field? (e.g. [0] -> name, and [1] -> role)
DozerBeanMapper mapper = new DozerBeanMapper();
BeanMappingBuilder builder = new BeanMappingBuilder() {
#Override
protected void configure() {
mapping(String[].class, User.class)
.fields(this_(), "name"); // HOW do I specify index?**
}
};
mapper.addMapping(builder);
List<String[]> users = new ArrayList<>();
String[] user1 = {"Jill", "SDE"};
String[] user2 = {"Jack", "PM"};
users.add(user1);
users.add(user2);
List<User> userList = mapObjects(mapper, users, User.class);
where mapObjects() is;
private static <T1, T2> List<T2> mapObjects(DozerBeanMapper mapper, List<T1> sourceList, Class<T2> destinationClazz) {
try {
return sourceList.stream()
.map(i -> mapper.map(i, destinationClazz))
.collect(Collectors.toList());
} catch (Exception e) {
...
}
return new ArrayList<>();
}
and User class;
class User {
String name;
String role;
// getter & setter
}
It worked perfectly with the following configuration;
DozerBeanMapper mapper = new DozerBeanMapper();
BeanMappingBuilder builder = new BeanMappingBuilder() {
#Override
protected void configure() {
mapping(String[].class, User.class)
.fields(this_(), "name", FieldsMappingOptions.customConverterId("arrToName"))
.fields(this_(), "role", FieldsMappingOptions.customConverterId("arrToRole"));
}
};
final Map<String, CustomConverter> customConverterMap = new HashMap<>();
customConverterMap.put("arrToName", new ArrToNameConverter());
customConverterMap.put("arrToRole", new ArrToRoleConverter());
mapper.setCustomConvertersWithId(customConverterMap);
mapper.addMapping(builder);
Utilizing a logic where String[] is mapped into name and role fields separately via custom converters, which are targeting a specific index of the input String[]. With dozer, you can essentially define custom converters and assign them an id, and refer them with those ids inside of field mappings FieldsMappingOptions.customConverterId("{id}")
where ArrToNameConverter;
public class ArrToNameConverter extends DozerConverter<String[], String> {
public ArrToNameConverter() {
super(String[].class, String.class);
}
#Override
public String convertTo(String[] strings, String user) {
return strings[0];
}
#Override
public String[] convertFrom(String user, String[] strings) {
return new String[0];
}
}
and ArrToRoleConverter;
public class ArrToRoleConverter extends DozerConverter<String[], String> {
public ArrToRoleConverter() {
super(String[].class, String.class);
}
#Override
public String convertTo(String[] strings, String user) {
return strings[1];
}
#Override
public String[] convertFrom(String user, String[] strings) {
return new String[0];
}
}
With the above mapper, I was able to get the following result;
[User(name=Jill, role=SDE), User(name=Jack, role=PM)]
Related
I am trying to read a JSON into the class. Jackson wants to apply a field of a subelement to the element itself, where it of course does not exist.
This is the JSON:
{
"authorizationRequest":{
"scope":["write","read"],
"resourceIds":["metadata"],
"approved":true,
"authorities":[],
"authorizationParameters":{
"scope":"write read",
"response_type":"token",
"redirect_uri":"",
"state":"",
"stateful":"false",
"client_id":"5102686_metadata"
},
"approvalParameters":{},
"state":"",
"clientId":"5102686_metadata",
"redirectUri":"",
"responseTypes":["token"],
"denied":false
},
"credentials":"",
"clientOnly":false,
"name":"testuser"
}
The classes look like the following:
// The main class that I try do deserialize:
public class DeserializedOAuth2Authentication extends OAuth2Authentication{
private String name;
private boolean clientOnly;
private AuthorizationRequest authorizationRequest = new DefaultAuthorizationRequest("", new ArrayList<>());
public DeserializedOAuth2Authentication() {
super(new DefaultAuthorizationRequest("", new ArrayList<>()), null);
}
#Override
#JsonProperty
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Override
#JsonProperty
public boolean isClientOnly() {
return clientOnly;
}
public void setClientOnly(boolean clientOnly) {
this.clientOnly = clientOnly;
}
#Override
#JsonProperty
public AuthorizationRequest getAuthorizationRequest() {
return authorizationRequest;
}
public void setAuthorizationRequest(AuthorizationRequest authorizationRequest) {
this.authorizationRequest = authorizationRequest;
}
}
AuthorizationRequest is an interface with all the getters for the listed elements; it is configured to be serialized by a DefaultAuthorizationRequest class also containing the respective setters and implementing fileds with corresponding names.
public class DefaultAuthorizationRequest implements AuthorizationRequest, Serializable {
private Set<String> scope = new LinkedHashSet<String>();
private Set<String> resourceIds = new HashSet<String>();
private boolean approved = false;
private Collection<GrantedAuthority> authorities = new HashSet<GrantedAuthority>();
private Map<String, String> authorizationParameters = new ConcurrentHashMap<String, String>();
private Map<String, String> approvalParameters = new HashMap<String, String>();
private String resolvedRedirectUri;
public Map<String, String> getAuthorizationParameters() {
return Collections.unmodifiableMap(authorizationParameters);
}
public Map<String, String> getApprovalParameters() {
return Collections.unmodifiableMap(approvalParameters);
}
public String getClientId() {
return authorizationParameters.get(CLIENT_ID);
}
public Set<String> getScope() {
return Collections.unmodifiableSet(this.scope);
}
public Set<String> getResourceIds() {
return Collections.unmodifiableSet(resourceIds);
}
public Collection<GrantedAuthority> getAuthorities() {
return Collections.unmodifiableSet((Set<? extends GrantedAuthority>) authorities);
}
public boolean isApproved() {
return approved;
}
public boolean isDenied() {
return !approved;
}
public String getState() {
return authorizationParameters.get(STATE);
}
public String getRedirectUri() {
return resolvedRedirectUri == null ? authorizationParameters.get(REDIRECT_URI) : resolvedRedirectUri;
}
public Set<String> getResponseTypes() {
return OAuth2Utils.parseParameterList(authorizationParameters.get(RESPONSE_TYPE));
}
public void setRedirectUri(String redirectUri) {
this.resolvedRedirectUri = redirectUri;
}
public void setScope(Set<String> scope) {
this.scope = scope == null ? new LinkedHashSet<String>() : new LinkedHashSet<String>(scope);
authorizationParameters.put(SCOPE, OAuth2Utils.formatParameterList(scope));
}
public void setResourceIds(Set<String> resourceIds) {
this.resourceIds = resourceIds == null ? new HashSet<String>() : new HashSet<String>(resourceIds);
}
public void setApproved(boolean approved) {
this.approved = approved;
}
public void setAuthorities(Collection<? extends GrantedAuthority> authorities) {
this.authorities = authorities == null ? new HashSet<GrantedAuthority>() : new HashSet<GrantedAuthority>(
authorities);
}
public void setAuthorizationParameters(Map<String, String> authorizationParameters) {
String clientId = getClientId();
Set<String> scope = getScope();
this.authorizationParameters = authorizationParameters == null ? new HashMap<String, String>()
: new HashMap<String, String>(authorizationParameters);
}
public void setApprovalParameters(Map<String, String> approvalParameters) {
this.approvalParameters = approvalParameters == null ? new HashMap<String, String>()
: new HashMap<String, String>(approvalParameters);
}
....
}
On calling read on the above JSON string I get an exception
com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "scope" (class de.mvbonline.vlx.auth.oauth2.DeserializedOAuth2Authentication), not marked as ignorable (3 known properties: "name", "authorizationRequest", "clientOnly"])
at [Source: (String)"{ "credentials":"", "clientOnly":false, "authorizationRequest":{ "scope":["write","read"], "resourceIds":["metadata"], "approved":true, "authorities":[], "authorizationParameters":{ "scope":"write read", "response_type":"token", "redirect_uri":"", "state":"", "stateful":"false", "[truncated 316 chars]; line: 1, column: 111] (through reference chain: de.mvbonline.vlx.auth.oauth2.DeserializedOAuth2Authentication["scope"])
Of course the field "scope" is not in the context of DeserializedOAuth2Authentication, but in the context of DefaultAuthorizationRequest. Why is Jackson searching in the wrong class for it?
I am unsing Jackson version 2.12.4
Make sure that DefaultAuthorizationRequest can be serialized and deserialized by Jackson. I guess that they are not for several reasons. Two that I can think of:
You have to let Jackson know how to deserialize DefaultAuthorizationRequest class. One possible solution would be to add a #JsonCreator and #JsonProperty to the class. The same applies to GrantedAuthority class.
DefaultAuthorizationRequest has fields of type Map, which need special attention. See these links on how to convert a JSON String to a Map<String, String> or, if the Map has custom objects, how to deserialize into a HashMap of custom objects
Also, you can take a look at Map Serialization and Deserialization with Jackson
I found my problem.
I formerly mapped my concrete implementation of the interface AuthorizationRequest via a handler:
mapper.addHandler(new DeserializationProblemHandler() {
#Override
public Object handleMissingInstantiator(DeserializationContext ctxt, Class<?> instClass, ValueInstantiator valueInsta, JsonParser p, String msg) throws IOException {
if(instClass.isAssignableFrom(AuthorizationRequest.class)) {
return new DeserializedAuthorizationRequest();
}
return super.handleMissingInstantiator(ctxt, instClass, valueInsta, p, msg);
}
});
This seems to be definitely not the same as annotating the field with the concrete class. This now works without problems:
public class DeserializedOAuth2Authentication extends OAuth2Authentication{
...
#Override
#JsonProperty("authorizationRequest")
#JsonDeserialize(as = DeserializedAuthorizationRequest.class)
public AuthorizationRequest getAuthorizationRequest() {
return authorizationRequest;
}
public void setAuthorizationRequest(AuthorizationRequest authorizationRequest) {
this.authorizationRequest = authorizationRequest;
}
}
This is the code for getting retrofit response as an object. The below method is working fine but I need an one common function for performing the above functionality, i.e the class name may vary. (e.g) ticket, price, token, appointment like this:
processGETRequest(AppController.getApiHelper().searchTickets(from, to), new RetrofitListener() {
#Override
public void onSuccess(Object object) { }
#Override
public void onSuccess(List<Object> object) {
// Here I'm getting retrofit response as a object //
if (object != null) {
// Below method is working fine //
List<Ticket> ticketList = new ArrayList<>();
for (Object result : object) {
String json = new Gson().toJson(result);
Ticket model = new Gson().fromJson(json, Ticket.class);
ticketList.add(model);
}
// I need an one common function for performing above functionality
// i.e the Class name may vary.. (e.g) Ticket, Price, Token, Appointment like this.
}
}
#Override
public void onError(String error) {
Log.d("error: ", " " + error);
}
}, false);
The RetrofitListener interface is simply:
public interface RetrofitListener {
void onSuccess(Object object);
void onSuccess(List<Object> object);
void onError(String error);
}
You can use a static function similar to:
static <T> List<T> toList(List<Object> object, Class<T> desiredClass) {
List<T> transformedList = new ArrayList<>();
if (object != null) {
for (Object result : object) {
String json = new Gson().toJson(result);
T model = new Gson().fromJson(json, desiredClass);
transformedList.add(model);
}
}
return transformedList;
}
Basically you just need to ensure that you deliver the desired type (e.g. desiredClass) and use it in fromJson.
Sample usage:
List<Ticket> ticketList = toList(object, Ticket.class);
List<Price> priceList = toList(object, Price.class);
Note that by moving the object != null into the toList-method you do not need to care about what is passed to that method. You at least get an empty list in return.
<T> List<T> getList(Class<T> type, List<Object> object) {
return object.stream()
.map(result -> new Gson().toJson(result))
.map(new Gson().fromJson(json, type))
.collect(Collectors.toList());
}
List<Ticket> ticketList = getList(Ticket.class, object);
This will do what your for-loop did.
You can convert the snippet
if (object != null) {
List<Ticket> ticketList = new ArrayList<>();
for (Object result : object) {
String json = new Gson().toJson(result);
Ticket model = new Gson().fromJson(json, Ticket.class);
ticketList.add(model);
}
}
with generics like this
<T> void check(Class<T> type, List<Object> object) {
List<T> ticketList = new ArrayList<>();
for (Object result : object) {
String json = new Gson().toJson(result);
T model = new Gson().fromJson(json, type);
ticketList.add(model);
}
}
As according to your question you want a generic code to get List which can be of Any? type.
List<Ticket> ticketList = new ArrayList<>();
for (Object result : object) {
String json = new Gson().toJson(result);
Ticket model = new Gson().fromJson(json, Ticket.class);
ticketList.add(model);
}
is this what you want?
List<Ticket> ticketList // can be List<T>??
Then create a generic method to get list and use it any where:
public <T> List<T> getObjectToList(Object obj, Class<T[]> ObjectArryaClass) {
String json = new Gson().toJson(obj);
return Arrays.asList(new Gson().fromJson(json, ObjectArryaClass));
}
call above method as:
#Override
public void onSuccess(List<Object> object) {
// Here I'm getting retrofit response as a object //
if (object != null) {
// Below method is working fine //
List<Ticket> ticketList = getObjectToList(object,Ticket[].class)
// I need an one common function for performing above functionality
// i.e the Class name may vary.. (e.g) Ticket, Price, Token, Appointment like this.
}
}
I'm trying to unit test a class having the following function:
private String getTabSeparateValues(final QueryParams params, final HttpServletRequest request) {
MetricsSerializer serializer = new MetricsSerializer();
return serializer.serializeValues(params, request);
}
It calls the "serializeValues(params,request)" function in the following class:
public class MetricsSerializer {
private final StringJoiner stringJoiner = new StringJoiner("\t");
private static final String MONTH_FORMAT = "MMMMM";
public String serializeMetrics(final QueryParams queryParams, final HttpServletRequest request) {
addValueFromString(queryParams.getId());
addValueFromString(getCurrentMonth());
addValueFromString(request.getRemoteUser().split("#")[0]);
addValueFromString(queryParams.getCurrency());
addValuesFromList(queryParams.getCompanies());
addValueFromString(queryParams.getCognosDatasetType());
addValuesFromList(queryParams.getScenarios());
addFilter(queryParams.getFilters());
addGroupings(queryParams.getGroupings());
addValueFromString(queryParams.getReportTemplate());
return stringJoiner.toString();
}
private void addValueFromString(final String value) {
stringJoiner.add(value);
}
private void addFilter(final List<Map<String, List<String>>> filters) {
List<String> collect = filters.stream()
.flatMap(entry -> entry.keySet()
.stream())
.collect(Collectors.toList());
addValuesFromList(collect);
}
private void addGroupings(final Map<String, List<String>> groupings) {
addValuesFromList(new ArrayList<>(groupings.keySet()));
}
private void addValuesFromList(final List<String> listValues) {
stringJoiner.add(listValues.stream().collect(Collectors.joining(" ")));
}
private String getCurrentMonth() {
DateFormat monthFormat = new SimpleDateFormat(MONTH_FORMAT);
return monthFormat.format(new Date());
}
}
This class returns the values in a tab-separated format. The structure of the QueryParams class is as follows:
#Data
#Builder
public class QueryParams {
private String datasetType;
private Map<String, List<String>> groupings;
private List<Aggregate> aggregates;
private List<String> scenarios;
private List<String> companies;
private List<Map<String, List<String>>> filters;
private List<NamedTimeRange> timeRanges;
private Map<String, String> params;
private String reportTemplate;
private String id;
private String currency;
}
I am not using all of the parameters in the QueryParameters (Skipping timeranges, params, aggregates). In order to test if I'm actually getting tab-separated metrics, I wrote the following test:
public class MetricsHandlerTest {
private QueryParams queryParams;
#Before
public void setUp() throws Exception {
List<String> list = Arrays.asList("one", "two");
List<String> scenarioList = Arrays.asList("A1");
List<Map<String, List<String>>> filter = new ArrayList<>();
Map<String, List<String>> filtersMap = new HashMap<>();
List<String> filterList = Arrays.asList("COM");
filtersMap.put("product", filterList);
filter.add(filtersMap);
queryParams = QueryParams.builder()
.id("123").currency("USD").companies(list).scenarios(scenarioList).filters(filter)
.build();
}
#Test
public void tabSerializerTest() {
String remoteUser = "testuser";
HttpServletRequest httpServletRequest = Mockito.mock(HttpServletRequest.class);
Mockito.when(httpServletRequest.getRemoteUser())
.thenReturn(remoteUser);
MetricsSerializer metricsSerializer = new MetricsSerializer();
String tabs = metricsSerializer.serializeMetrics(queryParams, httpServletRequest);
assertEquals(tabs, "123 \t USD \t one two");
}
}
I'm getting a null pointer exception for groupings. (in "addGroupings" of MetricsSerializer class) I tried logging groupings and it can be null. For scenarios and filters, I have added values. How do I handle this for groupings where it can be null?
Any help regarding how to fix this would be greatly appreciated.
I am not sure if I understand your issue. Is MetricsSerializer under your control? If so then you need to make it defensive to have null check to handle the case where groupings is null.
If it is outside of your control, then you need to build your query with an empty Group(rather than null) like this
queryParams = QueryParams.builder().withGroupings(new HashMap<String,List<String>>()).build();
I am trying to convert my POJO into 2 different CSV representations.
My POJO:
#NoArgsConstructor
#AllArgsConstructor
public static class Example {
#JsonView(View.Public.class)
private String a;
#JsonView(View.Public.class)
private String b;
#JsonView(View.Internal.class)
private String c;
#JsonView(View.Internal.class)
private String d;
public static final class View {
interface Public {}
interface Internal extends Public {}
}
}
Public view exposed fields a and b, and Internal view exposes all fields.
The problem is that if I construct the ObjectWriter with .writerWithSchemaFor(Example.class) all my fields are included but ignored as defined by the view. ObjectWriter will create the schema as defined by the Example.class but if I apply .withView it will only hide the fields, not ignore them.
This means that I must construct the schema manually.
Tests:
#Test
public void testJson() throws JsonProcessingException {
final ObjectMapper mapper = new ObjectMapper();
final Example example = new Example("1", "2", "3", "4");
final String result = mapper.writerWithView(Example.View.Public.class).writeValueAsString(example);
System.out.println(result); // {"a":"1","b":"2"}
}
#Test
public void testCsv() throws JsonProcessingException {
final CsvMapper mapper = new CsvMapper();
final Example example = new Example("1", "2", "3", "4");
final String result = mapper.writerWithSchemaFor(Example.class).withView(Example.View.Public.class).writeValueAsString(example);
System.out.println(result); // 1,2,,
}
#Test
public void testCsvWithCustomSchema() throws JsonProcessingException {
final CsvMapper mapper = new CsvMapper();
CsvSchema schema = CsvSchema.builder()
.addColumn("a")
.addColumn("b")
.build();
final Example example = new Example("1", "2", "3", "4");
final String result = mapper.writer().with(schema).withView(Example.View.Public.class).writeValueAsString(example);
System.out.println(result); // 1,2
}
testCsv test has 4 fields, but 2 are excluded. testCsvWithCustomSchema test has only the fields I want.
Is there a way to get CsvSchema that will match my #JsonView without having to construct it myself?
Here is a solution I did with reflection, I am not really happy with it since it is still "manually" building the schema.
This solution is also bad since it ignores mapper configuration like MapperFeature.DEFAULT_VIEW_INCLUSION.
This seems like doing something that should be already available from the library.
#AllArgsConstructor
public class GenericPojoCsvSchemaBuilder {
public CsvSchema build(final Class<?> type) {
return build(type, null);
}
public CsvSchema build(final Class<?> type, final Class<?> view) {
return build(CsvSchema.builder(), type, view);
}
public CsvSchema build(final CsvSchema.Builder builder, final Class<?> type) {
return build(builder, type, null);
}
public CsvSchema build(final CsvSchema.Builder builder, final Class<?> type, final Class<?> view) {
final JsonPropertyOrder propertyOrder = type.getAnnotation(JsonPropertyOrder.class);
final List<Field> fieldsForView;
// DO NOT use Arrays.asList because it uses an internal fixed length implementation which cannot use .removeAll (throws UnsupportedOperationException)
final List<Field> unorderedFields = Arrays.stream(type.getDeclaredFields()).collect(Collectors.toList());
if (propertyOrder != null && propertyOrder.value().length > 0) {
final List<Field> orderedFields = Arrays.stream(propertyOrder.value()).map(s -> {
try {
return type.getDeclaredField(s);
} catch (final NoSuchFieldException e) {
throw new IllegalArgumentException(e);
}
}).collect(Collectors.toList());
if (propertyOrder.value().length < type.getDeclaredFields().length) {
unorderedFields.removeAll(orderedFields);
orderedFields.addAll(unorderedFields);
}
fieldsForView = getJsonViewFields(orderedFields, view);
} else {
fieldsForView = getJsonViewFields(unorderedFields ,view);
}
final JsonIgnoreFieldFilter ignoreFieldFilter = new JsonIgnoreFieldFilter(type.getDeclaredAnnotation(JsonIgnoreProperties.class));
fieldsForView.forEach(field -> {
if (ignoreFieldFilter.matches(field)) {
builder.addColumn(field.getName());
}
});
return builder.build();
}
private List<Field> getJsonViewFields(final List<Field> fields, final Class<?> view) {
if (view == null) {
return fields;
}
return fields.stream()
.filter(field -> {
final JsonView jsonView = field.getAnnotation(JsonView.class);
return jsonView != null && Arrays.stream(jsonView.value()).anyMatch(candidate -> candidate.isAssignableFrom(view));
})
.collect(Collectors.toList());
}
private class JsonIgnoreFieldFilter implements ReflectionUtils.FieldFilter {
private final List<String> fieldNames;
public JsonIgnoreFieldFilter(final JsonIgnoreProperties jsonIgnoreProperties) {
if (jsonIgnoreProperties != null) {
fieldNames = Arrays.asList(jsonIgnoreProperties.value());
} else {
fieldNames = null;
}
}
#Override
public boolean matches(final Field field) {
if (fieldNames != null && fieldNames.contains(field.getName())) {
return false;
}
final JsonIgnore jsonIgnore = field.getDeclaredAnnotation(JsonIgnore.class);
return jsonIgnore == null || !jsonIgnore.value();
}
}
}
I've created a DataGrid so:
DataGrid<String> grid = new DataGrid<String>();
grid.setPageSize(4);
TextColumn<String> date = new TextColumn<String>() {
public String getValue(String object) {
return object;
}
};
grid.addColumn(date, "Date");
TextColumn<String> time = new TextColumn<String>() {
public String getValue(String object) {
return object;
}
};
grid.addColumn(time, "Time");
TextColumn<String> number = new TextColumn<String>() {
public String getValue(String object) {
return object;
}
};
grid.addColumn(number, "Number");
Now I'd like to populate it but I don't understood how to do it because I have these String[] and they must be splitted also:
textString[1]="01/01/2014;10:00;300";
textString[2]="02/02/2014;11:00;400"; ...
Thanks in advance.
UPDATE
#Sturmination I followed your hint but there is another problem for this code(assuming that splitting is done):
..
protected static List<Example> EXAMPLES = null;
..
public void method() {
...
EXAMPLES = Arrays.asList(new Example("01/01/2014", "10:00", "300"));
grid.setRowCount(EXAMPLES.size(), true);
grid.setRowData(0, EXAMPLES);
..
}
It returns this error:
The method setRowData(int, List<? extends String>) in the type AbstractHasData<String> is not applicable for the arguments (int, List<Example>)
And it suggests : Change type of EXAMPLES to List<? extends String> but it doesn't work anyway.
Have you tried this:
DataGrid<String> grid = new DataGrid<String>();
grid.setPageSize(4);
TextColumn<String> date = new TextColumn<String>() {
public String getValue(String object) {
return object.split(';')[0];
}
};
grid.addColumn(date, "Date");
TextColumn<String> time = new TextColumn<String>() {
public String getValue(String object) {
return object.split(';')[1];
}
};
grid.addColumn(time, "Time");
TextColumn<String> number = new TextColumn<String>() {
public String getValue(String object) {
return object.split(';')[2];
}
};
grid.addColumn(number, "Number");
A nicer approach would be to create a new Java Bean for your rows and convert your String[] items to a List<Row> of the new row objects
You can use String[] in your code:
DataGrid<String> grid = new DataGrid<String>();
TextColumn<String[]> date = new TextColumn<String[]>() {
public String getValue(String[] object) {
return object[0];
}
};
Split your strings when you add them:
private ListDataProvider<String[]> dataProvider = new ListDataProvider<String[]>();
private List<String[]> displayItems = dataProvider.getList();
...
for (String textString : textStrings) {
displayItems.add(textString.split(";");
}
I would do it like this, if size of you data is not huge.
Create a class
Class YourClass{
private String date, time, number;
public YourClass(String date, String time, String nuber){
this.date=date;
this.time=time;
this.number=number;
}
//getters and setters here
}
Create a method to conver you values
private List<YourObject> convert(String[] values){
List<YourClass> data= new ArrayList<YourClass>();
String date, time, number;
for(i=0; values.size(); i++){
values[i] //split the string and asign values to date, time and number
dataList.add(new YourClass(date, time, number));
}
return dataList;
}
Add you values to DataGrid
ListDataProvider<YourClass> provider= new ListDataProvider<YourClass>();
List<YourClass> dataList = new ArrayList<YourClass>();
dataList.addAll(convert(textString[]));
provider.addDataDisplay(grid);
provider.setList(dataList);
Then in your Columns just:
return object.getDate();
return object.getTime();
return object.getNumber();