I have a list of objects instantiated in a return class in a service's response. But when this list has 1 position, it is returning as an object and not as a list. can anybody help me?
#XmlRootElement(name = "exame")
public class ExameVO implements Serializable {
private static final long serialVersionUID = -5840337332057658386L;
private long id;
#NotNull
private String cpf;
#NotNull
private String dataNascimento;
#NotNull
private int tipoExame;
#NotNull
private String excluido;
private List<ExameArquivoVO> resultadoExameArquivos;
private String observacao;
private String dataInclusao;
public ExameVO() {
super();
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getCpf() {
return cpf;
}
public void setCpf(String cpf) {
this.cpf = cpf;
}
public String getDataNascimento() {
return dataNascimento;
}
public void setDataNascimento(String dataNascimento) {
this.dataNascimento = dataNascimento;
}
public int getTipoExame() {
return tipoExame;
}
public void setTipoExame(int tipoExame) {
this.tipoExame = tipoExame;
}
public String getObservacao() {
return observacao;
}
public void setObservacao(String observacao) {
this.observacao = observacao;
}
public String getExcluido() {
return excluido;
}
public void setExcluido(String excluido) {
this.excluido = excluido;
}
public List<ExameArquivoVO> getResultadoExameArquivos() {
return resultadoExameArquivos;
}
public void setResultadoExameArquivos(List<ExameArquivoVO> resultadoExameArquivos) {
this.resultadoExameArquivos = resultadoExameArquivos;
}
public String getDataInclusao() {
return dataInclusao;
}
public void setDataInclusao(String dataInclusao) {
this.dataInclusao = dataInclusao;
}
public static long getSerialversionuid() {
return serialVersionUID;
}
#Override
public String toString() {
return "ResultadoExameVO [id=" + id + ", cpf=" + cpf + ", dataNascimento=" + dataNascimento + ", tipoExame="
+ tipoExame + ", observacao=" + observacao + ", excluido=" + excluido + ", dataInclusao=" + dataInclusao
+ ", resultadoExameArquivos=" + resultadoExameArquivos + "]";
}
}
#Override
public List<ExameVO> listarExames(String cpf, String dtNascimento, Long tipoExame) throws WebServiceException {
List<ExameVO> examesVO = new ArrayList<ExameVO>();
try {
examesVO = exameDAO.listarExames(cpf, dtNascimento, tipoExame);
if(!examesVO.isEmpty()) {
for(ExameVO exameVO : examesVO) {
exameVO.setResultadoExameArquivos(new ArrayList<ExameArquivoVO>());
exameVO.getResultadoExameArquivos().addAll(exameDAO.listarExameArquivos(exameVO.getId()));
}
}
return examesVO;
} catch (Exception e) {
throw new WebServiceException(e);
}
}
Response to postman: Notice that there is 1 object that has 2 objects inside the file list and another object that has 1 and it returns as an object and not as a list with 1 object.
I have a problem. I have the following class:
public class Cross implements Comparable<Cross> {
private Long openTime;
private String market;
private String coin;
private String period;
private String metric1;
private String metric2;
private Double close;
private String trend;
public Long getOpenTime() {
return this.openTime;
}
public void setOpenTime(long openTime) {
this.openTime = openTime;
}
public String getMarket() {
return this.market;
}
public void setMarket(String market) {
this.market = market;
}
public String getCoin() {
return this.coin;
}
public void setCoin(String coin) {
this.coin = coin;
}
public String getPeriod() {
return this.period;
}
public void setPeriod(String period) {
this.period = period;
}
public String getMetric1() {
return this.metric1;
}
public void setMetric1(String metric1) {
this.metric1 = metric1;
}
public String getMetric2() {
return this.metric2;
}
public void setMetric2(String metric2) {
this.metric2 = metric2;
}
public Double getClose() {
return this.close;
}
public void setClose(double close) {
this.close = close;
}
public String getTrend() {
return this.trend;
}
#Override
public boolean equals(Object object) {
if (object != null && object instanceof Cross) {
Cross cross = (Cross) object;
return (
openTime.equals(cross.getOpenTime()) &&
market.equals(cross.getMarket()) &&
coin.equals(cross.getCoin()) &&
period.equals(cross.getPeriod()) &&
metric1.equals(cross.getMetric1()) &&
metric2.equals(cross.getMetric2())
);
}
return false;
}
#Override
public int compareTo(Cross o) {
return this.getOpenTime().compareTo(o.getOpenTime());
}
}
Now I have a list containing 500 objects of these elements. Here are the first 4 shown:
{ openTime='1504332000000', market='USDT', coin='ETH', period='2h', metric1='EMA12', metric2='EMA26', close='363.7', trend='Down'}
{ openTime='1504663200000', market='USDT', coin='ETH', period='2h', metric1='EMA12', metric2='EMA26', close='325.73', trend='Up'}
{ openTime='1504879200000', market='USDT', coin='ETH', period='2h', metric1='EMA12', metric2='EMA26', close='294.05', trend='Down'}
{ openTime='1505181600000', market='USDT', coin='ETH', period='2h', metric1='EMA12', metric2='EMA26', close='304.41', trend='Up'}
In a variable I have stored the epoch of a specific datetime and with that I want to find the first valid cross, so I tried this:
private Cross getValidCross(List<Cross> crossList, LocalDateTime runDateTimeGMT0) {
long searchEpoch = runDateTimeGMT0.toEpochSecond(ZoneOffset.UTC) * 1000;
return crossList.stream().filter(cross -> cross.getOpenTime() < searchEpoch).max(Cross::compareTo).orElse(null);
}
But this code returns the value null When my searchEpoch is for example: 1514764800000. In the list I do see multiple objects that have a lower openTime than the searchEpoch. The result I want is the cross with the highest openTime, but it still has to be smaller than the searchEpoch.
Here is the error I get:
runDateTimeGMT0: 2018-01-01T00:00
Exception in thread "main" java.lang.reflect.InvocationTargetException
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:64)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:564)
at com.hatop.drivers.SimulatorDriver.run(SimulatorDriver.java:297)
at com.hatop.drivers.HatopDriver.main(HatopDriver.java:120)
Caused by: java.lang.NullPointerException: Cannot invoke "com.hatop.models.Cross.getTrend()" because the return value of "com.hatop.drivers.HatopDriver.getValidCross(List<Cross>, LocalDateTime)"
is null
at com.hatop.strategies.modules.module_java001.run(module_java001.java:186)
... 6 more
Why is my return value null?
This is caused due to the value the argument runDateTimeGMT0 is given and this:
long searchEpoch = runDateTimeGMT0.toEpochSecond(ZoneOffset.UTC) * 1000;
Since this is working:
public class Demo {
private static Cross getValidCross(List<Cross> crossList, LocalDateTime runDateTimeGMT0) {
long searchEpoch = 1514764800000L;
return crossList.stream()
.filter(cross -> cross.getOpenTime() < searchEpoch)
.max(Cross::compareTo)
.orElse(null);
}
#SneakyThrows
public static void main(String[] args) {
List<Cross> crosses = Arrays.asList(
new Cross(1504332000000L, "USDT", "ETH", "2h", "EMA12", "EMA26", 363.7, "Down"),
new Cross(1504663200000L, "USDT", "ETH", "2h", "EMA12", "EMA26", 325.73, "Up"),
new Cross(1504879200000L, "USDT", "ETH", "2h", "EMA12", "EMA26", 294.05, "Down"),
new Cross(1505181600000L, "USDT", "ETH", "2h", "EMA12", "EMA26", 304.41, "Up")
);
Cross validCross = getValidCross(crosses, null);
System.out.println(validCross);
}
}
Output:
Cross(openTime=1505181600000, market=USDT, coin=ETH, period=2h, metric1=EMA12, metric2=EMA26, close=304.41, trend=Up)
By the way, equals() is implemented without hashcode() - a recipe for problems.
I tested you code by passing the value in a proper Cross constructor, as it appears in your list and it works fine. In particular, openingTime is passed as primitive type long.
The issue is NOT in the filter, as you can definitely use any operator with Long type.
In my opinion, there is something wrong in the file format of your Cross object. Highly likely is because of the openingTime field's value, which is probably converted in the wrong value.
Here is the test I wrote:
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.List;
public class TestCross {
public static void main(String[] args) {
List<Cross> crossList = List.of(new Cross(1504332000000L,"USDT", "ETH", "2h","EMA12", "EMA26",363.7,"Down" ),
new Cross(1505181600000L,"USDT", "ETH", "2h","EMA12", "EMA26",304.41,"Up" ),
new Cross(1504663200000L,"USDT", "ETH", "2h","EMA12", "EMA26",325.73,"Up" ),
new Cross(1504879200000L,"USDT", "ETH", "2h","EMA12", "EMA26",294.05,"Down" ));
Cross cross = new TestCross().getValidCross(crossList, LocalDateTime.now());
System.out.println(cross);
}
private Cross getValidCross(List<Cross> crossList, LocalDateTime runDateTimeGMT0) {
long searchEpoch = runDateTimeGMT0.toEpochSecond(ZoneOffset.UTC) * 1000;
return crossList.stream().filter(cross -> cross.getOpenTime() < searchEpoch).max(Cross::compareTo).orElse(null);
}
}
Cross class
public class Cross implements Comparable<Cross> {
public Cross(Long openTime, String market, String coin, String period, String metric1, String metric2, Double close,
String trend) {
super();
this.openTime = openTime;
this.market = market;
this.coin = coin;
this.period = period;
this.metric1 = metric1;
this.metric2 = metric2;
this.close = close;
this.trend = trend;
}
private Long openTime;
private String market;
private String coin;
private String period;
private String metric1;
private String metric2;
private Double close;
private String trend;
public Long getOpenTime() {
return this.openTime;
}
public void setOpenTime(long openTime) {
this.openTime = openTime;
}
public String getMarket() {
return this.market;
}
public void setMarket(String market) {
this.market = market;
}
public String getCoin() {
return this.coin;
}
public void setCoin(String coin) {
this.coin = coin;
}
public String getPeriod() {
return this.period;
}
public void setPeriod(String period) {
this.period = period;
}
public String getMetric1() {
return this.metric1;
}
public void setMetric1(String metric1) {
this.metric1 = metric1;
}
public String getMetric2() {
return this.metric2;
}
public void setMetric2(String metric2) {
this.metric2 = metric2;
}
public Double getClose() {
return this.close;
}
public void setClose(double close) {
this.close = close;
}
public String getTrend() {
return this.trend;
}
#Override
public boolean equals(Object object) {
if (object != null && object instanceof Cross) {
Cross cross = (Cross) object;
return (
openTime.equals(cross.getOpenTime()) &&
market.equals(cross.getMarket()) &&
coin.equals(cross.getCoin()) &&
period.equals(cross.getPeriod()) &&
metric1.equals(cross.getMetric1()) &&
metric2.equals(cross.getMetric2())
);
}
return false;
}
#Override
public String toString() {
return "Cross [openTime=" + openTime + ", market=" + market + ", coin=" + coin + ", period=" + period
+ ", metric1=" + metric1 + ", metric2=" + metric2 + ", close=" + close + ", trend=" + trend + "]";
}
#Override
public int compareTo(Cross o) {
return this.getOpenTime().compareTo(o.getOpenTime());
}
}
And here is the output:
Cross [openTime=1505181600000, market=USDT, coin=ETH, period=2h, metric1=EMA12, metric2=EMA26, close=304.41, trend=Up]
So I have this POJO class:
public class Player {
#CsvBindByName
private String simTime;
#CsvBindByName
private String playerId;
#CsvBindByName
private String dimX;
#CsvBindByName
private String offX;
#CsvBindByName
private String dimY;
#CsvBindByName
private String roadS;
#CsvBindByName
private String roadT;
public String getSimTime() {
return simTime;
}
public void setSimTime(String simTime) {
this.simTime = simTime;
}
public String getPlayerId() {
return playerId;
}
public void setPlayerId(String playerId) {
this.playerId = playerId;
}
public String getDimX() {
return dimX;
}
public void setDimX(String dimX) {
this.dimX = dimX;
}
public String getOffX() {
return offX;
}
public void setOffX(String offX) {
this.offX = offX;
}
public String getDimY() {
return dimY;
}
public void setDimY(String dimY) {
this.dimY = dimY;
}
public String getRoadS() {
return roadS;
}
public void setRoadS(String roadS) {
this.roadS = roadS;
}
public String getRoadT() {
return roadT;
}
public void setRoadT(String roadT) {
this.roadT = roadT;
}
#Override
public String toString() {
return "Player{" + "simTime=" + simTime + ", playerId=" + playerId + ", dimX=" + dimX + ", offX=" + offX + ", dimY=" + dimY + ", roadS=" + roadS + ", roadT=" + roadT + '}';
}
}
And I have a large excel file with a LOT MORE columns. One of the columns in my excel file is called objectId.
Using this code:
private void loadCSVFiles() throws Exception {
List<Player> beans = new CsvToBeanBuilder(new FileReader("C:\\Users\\noname\\Desktop\\ABP_S31\\ABP20180809_S31_FG_Notbremsung_100.csv"))
.withType(Player.class)
.withIgnoreLeadingWhiteSpace(true)
.build()
.parse();
beans.forEach(System.out::println);
}
I managed to get specific columns which I need.
The problem I am having is that right now I only need rows where the playerId equals objectId. Obviously I could add objectId as a class property and after I load the file I could go through the entire list and filter the rows AGAIN. But I don't want to this as
performance issues
objectId has actually nothing to do with my Player class
Also I could load the entire excel file and filter the columns, but I also don't want this because for me personally it is more readable if I do this the current way. Is there a way to solve this problem or do I have to use the options above?
I tried using csvToBeanFilter but the getColumnIndex method is deprecated: docu
So if you know the column headers, and you're sure they won't change in the future, you could implement a CsvToBeanFilter using a custom HeaderColumnNameMappingStrategy. This way you can avoid the deprecated getColumnIndex() method.
private class MyStrategy<T> implements HeaderColumnNameMappingStrategy<T> {
private int playerIndex;
private int objectIndex;
#Override
public void captureHeader(CSVReader reader) throws IOException {
// make sure to call super() first because it will retrieve the header variable
super();
// inspect the header and store the relevant indices for later use
for(int i = 0; i < header.length; i++)
{
if("objectId".equals(header[i])
objectIndex = i;
else if("playerId".equals(header[i])
playerIndex = i;
}
}
public int getPlayerIndex(){ return playerIndex; }
public int getObjectIndex(){ return objectIndex; }
}
Use it in the Filter
private class MyFilter implements CsvToBeanFilter {
private final MappingStrategy strategy;
public MyFilter(MappingStrategy strategy) {
this.strategy = strategy;
}
public boolean allowLine(String[] line) {
// restore the relevant indices from the strategy
int playerIndex = strategy.getPlayerIndex();
int objectIndex = strategy.getObjectIndex();
String playerId = line[playerIndex];
String objectId = line[objectIndex];
return playerId.equals(objectId);
}
}
And now you can add the Filter to the CsvToBeanBuilder.
private void loadCSVFiles() throws Exception {
MappingStrategy strategy = new MyStrategy();
List<Player> beans = new CsvToBeanBuilder(new FileReader("C:\\Users\\noname\\Desktop\\ABP_S31\\ABP20180809_S31_FG_Notbremsung_100.csv"))
.withType(Player.class)
.withIgnoreLeadingWhiteSpace(true)
.withMapper(strategy)
.withFilter(new MyFilter())
.build()
.parse();
beans.forEach(System.out::println);
}
I tried to implement custom TiledDataSource for using with paging library. When I used LivePagedListProvider like returns type for my Dao method it worked fine (after table items updating - ui updated automatically).
#Query("SELECT * FROM " + Table.States.PLAY_STATE + ", "+Table.Chart.ARTIST+ " ORDER BY position ASC")
LivePagedListProvider<Artist> loadArtists();
But when I try implement custom TiledDataSource for LivePagerListProvider table updates not triggered my observers.
Abstract generic class:
public abstract class PagedNetworkBoundResource<ResultType, RequestType> extends TiledDataSource<ResultType> {
#Override
public int countItems() {
return DataSource.COUNT_UNDEFINED;
}
#Override
public List<ResultType> loadRange(int startPosition, int count) {
fetchFromNetwork(startPosition, count);
return loadFromDb(startPosition, count);
}
#WorkerThread
private void fetchFromNetwork(int startPosition, int count) {
if (createCall(startPosition, count) != null)
try {
Response<RequestType> response = createCall(startPosition, count).execute();
if (response.isSuccessful() && response.code() == 200) {
saveCallResult(response.body());
}
} catch (IOException e) {
e.printStackTrace();
}
}
#WorkerThread
protected abstract void saveCallResult(#NonNull RequestType item);
#WorkerThread
protected abstract List<ResultType> loadFromDb(int startPosition, int count);
#WorkerThread
protected abstract Call<RequestType> createCall(int startPosition, int count);
public LiveData<PagedList<ResultType>> getAsLiveData() {
return new LivePagedListProvider<Integer, ResultType>() {
#Override
protected DataSource<Integer, ResultType> createDataSource() {
return PagedNetworkBoundResource.this;
}
}.create(0, new PagedList.Config.Builder()
.setEnablePlaceholders(false)
.setPageSize(20)
.setInitialLoadSizeHint(20)
.build());
}
}
My dao method for this case:
#Query("SELECT * FROM " + Table.States.PLAY_STATE + ", "+Table.Chart.ARTIST+ " ORDER BY position ASC LIMIT (:limit) OFFSET (:offset)")
List<Artist> loadArtists(int offset, int limit);
I update Table.States.PLAY_STATE.
public void updatePlayerState(PlayerStateEntity state){
new Thread(() -> {
dao.deleteState();
dao.insertState(state);
}).run();
}
#Dao
public interface PlayStateDao {
#Insert(onConflict = OnConflictStrategy.REPLACE)
void insertState(PlayerStateEntity playEntity);
#Query("DELETE FROM " + Table.States.PLAY_STATE)
void deleteState();
#Query("SELECT * FROM "+Table.States.PLAY_STATE)
PlayerStateEntity getPlayerState();
}
#Entity(tableName = Table.States.PLAY_STATE)
public class PlayerStateEntity extends IdEntity {
#ColumnInfo(name = "album_played_id")
private Long albumPlayedId = -1L;
#ColumnInfo(name = "track_played_id")
private Long trackPlayedId = -1L;
#ColumnInfo(name = "artist_played_id")
private Long artistPlayedId = -1L;
#ColumnInfo(name = "state")
private PlayingState state;
#ColumnInfo(name = "playing_type")
private PlayingType playingType;
public Long getAlbumPlayedId() {
return albumPlayedId;
}
public void setAlbumPlayedId(Long albumPlayedId) {
this.albumPlayedId = albumPlayedId;
}
public Long getTrackPlayedId() {
return trackPlayedId;
}
public void setTrackPlayedId(Long trackPlayedId) {
this.trackPlayedId = trackPlayedId;
}
public Long getArtistPlayedId() {
return artistPlayedId;
}
public void setArtistPlayedId(Long artistPlayedId) {
this.artistPlayedId = artistPlayedId;
}
public PlayingState getState() {
return state;
}
public void setState(PlayingState state) {
this.state = state;
}
public PlayingType getPlayingType() {
return playingType;
}
public void setPlayingType(PlayingType playingType) {
this.playingType = playingType;
}
}
class Artist extends PlayEntity{
private String name;
private String link;
private String picture;
#ColumnInfo(name = "picture_small")
private String pictureSmall;
#ColumnInfo(name = "picture_medium")
private String pictureMedium;
#ColumnInfo(name = "picture_big")
private String pictureBig;
#ColumnInfo(name = "picture_xl")
private String pictureXl;
private Boolean radio;
private String tracklist;
private Integer position;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getLink() {
return link;
}
public void setLink(String link) {
this.link = link;
}
public String getPicture() {
return picture;
}
public void setPicture(String picture) {
this.picture = picture;
}
public String getPictureSmall() {
return pictureSmall;
}
public void setPictureSmall(String pictureSmall) {
this.pictureSmall = pictureSmall;
}
public String getPictureMedium() {
return pictureMedium;
}
public void setPictureMedium(String pictureMedium) {
this.pictureMedium = pictureMedium;
}
public String getPictureBig() {
return pictureBig;
}
public void setPictureBig(String pictureBig) {
this.pictureBig = pictureBig;
}
public String getPictureXl() {
return pictureXl;
}
public void setPictureXl(String pictureXl) {
this.pictureXl = pictureXl;
}
public Boolean getRadio() {
return radio;
}
public void setRadio(Boolean radio) {
this.radio = radio;
}
public String getTracklist() {
return tracklist;
}
public void setTracklist(String tracklist) {
this.tracklist = tracklist;
}
public Integer getPosition() {
return position;
}
public void setPosition(Integer position) {
this.position = position;
}
#Override
public boolean isItemPlaying() {
return getId() == getArtistPlayedId().longValue() && getPlayingType() == PlayingType.Artist && getState() == PlayingState.Playing;
}
}
public abstract class PlayEntity extends PlayerStateEntity {
public abstract boolean isItemPlaying();
}
public class ArtistsRepository {
private final ChartArtistDao chartArtistDao;
private final DeezerService deezerService;
#Inject
public ArtistsRepository(ChartArtistDao chartArtistDao, DeezerService deezerService) {
this.chartArtistDao = chartArtistDao;
this.deezerService = deezerService;
}
public LiveData<PagedList<ChartArtistDao.Artist>> getArtist() {
return new PagedNetworkBoundResource<ChartArtistDao.Artist, ModelList<ChartArtistEntity>>() {
#Override
protected void saveCallResult(#NonNull ModelList<ChartArtistEntity> item) {
if (item != null) {
chartArtistDao.saveArtists(item.getItems());
}
}
#Override
protected List<ChartArtistDao.Artist> loadFromDb(int startPosition, int count) {
return chartArtistDao.loadArtists(startPosition, count);
}
#Override
protected Call<ModelList<ChartArtistEntity>> createCall(int startPosition, int count) {
return deezerService.getChartArtist(startPosition, count);
}
}.getAsLiveData();
}
}
For each Artist items I add fields from PlayerStateEntity (not good solution but this easy way to represent state of ui items). After PlayerStateEntity table updates Room should notify about data changes, but doesn't do it.
I understand that Room doesn't know about query what I used, and can't updates my RecyclerView which provide by paging library. But maybe some one knows how to notify Room about tables which I used inside mine DataSource for future triggering ui updates?
The problem was related with custom DataSource realization. When data has changed, LivePagedListProvider should create a new DataSource instance for right ui updating. I used the same instance, so my previous solution is not right.
I am getting "Expected BEGIN_ARRAY but was STRING at line 1 column 1 path $" when I am retrieve the list from database.How to fix this issue where I am mistaken in my code..thanks in advance.
Json response I am getting is below,
[{
"eventId":1,
"ringeeUserId":2,
"text":"Reception1",
"place":"Erode",
"eventDate":"2015-10-03",
"startTime":"09:00 AM",
"endTime":"12:00 PM",
"isActive":0,
"isDelete":0,
"eventUserRelationBOs":[]
}]
EventBO class file is below,
package com.ringeeapp.service.businessobjects;
import java.io.Serializable;
import java.util.List;
public class EventBO implements Serializable {
private static final long serialVersionUID = 281625146097131515L;
private long eventId;
private long ringeeUserId;
private String text;
private String place;
private String eventDate;
private String startTime;
private String endTime;
private int isActive;
private int isDelete;
private List<EventUserRelationBO> eventUserRelationBOs;
public long getEventId() {
return eventId;
}
public void setEventId(long eventId) {
this.eventId = eventId;
}
public long getRingeeUserId() {
return ringeeUserId;
}
public void setRingeeUserId(long ringeeUserId) {
this.ringeeUserId = ringeeUserId;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public String getPlace() {
return place;
}
public void setPlace(String place) {
this.place = place;
}
public String getEventDate() {
return eventDate;
}
public void setEventDate(String eventDate) {
this.eventDate = eventDate;
}
public String getStartTime() {
return startTime;
}
public void setStartTime(String startTime) {
this.startTime = startTime;
}
public String getEndTime() {
return endTime;
}
public void setEndTime(String endTime) {
this.endTime = endTime;
}
public int getIsDelete() {
return isDelete;
}
public void setIsDelete(int isDelete) {
this.isDelete = isDelete;
}
public int getIsActive() {
return isActive;
}
public void setIsActive(int isActive) {
this.isActive = isActive;
}
public List<EventUserRelationBO> getEventUserRelationBOs() {
return eventUserRelationBOs;
}
public void setEventUserRelationBOs(List<EventUserRelationBO> eventUserRelationBOs) {
this.eventUserRelationBOs = eventUserRelationBOs;
}
}
The below code that process json data
public #ResponseBody String getAllInvites(#RequestParam("userBO") String userBo) {
List<EventBO> eventBOs = new ArrayList<EventBO>();
UserBO userBO = gson.fromJson(userBo, UserBO.class);
try {
eventBOs = manageEventServiceImpl.getAllInvites(userBO);
log.info("getting all events for user " + userBO.getRingeeUserId());
} catch (UserServiceException serExp) {
log.error("Error while getting event for userId id" + userBO.getRingeeUserId(), serExp);
}
return gson.toJson(eventBOs);
}
You have an array of EventBO, but trying to read as object. If you unmarshal like this:
EventBO bo = gson.fromJson(JSON, EventBO.class);
than you will receive error "java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 2 path $"
But if you change code to:
EventBO[] list = gson.fromJson(JSON, EventBO[].class);
you successfully unmarshal this json
P.S. Tested with Gson 2.4
Kotlin
Late answer and i don't think many face this issue but, i was dealing with a dumb server, that returned the data however it wanted, strange huh?
yes,
//response 1
{
"genre":"drama,thriller"
}
//response 2
{
"genre":null
}
//response 3
{
"genre":["drama", "action", "blah", "blah"]
}
You can think how unfair this is.
i so changed my genre's data type to Any?
like
data class Model(...
....
val genre:Any?
...
)
now to use it, i do something like this
movieInfo.mInfo.genre?.let {
if (it is String) {
tv_genre.text = it
} else if (it is List<*>) {
val builder = StringBuilder()
it.forEach {
if (it is String) {
builder.append(it)
}
}
tv_genre.text = builder.toString()
}
}