2

So, I've come across this situation

I have a Restful controller method which returns a list of objects Match

@RequestMapping(value = "/fetchFootballMatchesToday", method = RequestMethod.GET)
public @ResponseBody List<Match> fetchMatchesScheduledToday() throws ParseException {
    return matchesToday;
   }

The object Match has say 15 properties & I need only 3 properties on the UI. I do not want the user to see the other properties of the object.

There are two ways to do it:

  1. Run a for loop & explicitly set the properties to null, for every Match object, which are not meant to be sent to the UI. Like so

    List<Match> matchesToday = matchInvService.fetchMatchByDate(today);
    
    for (Match stats : matchesToday) {
     if (stats != null) {
    /* user should not know these details, so they are being set to null */
        stats.setMatchSuccessIndex(null);
        stats.setTeamRanking(null);
        stats.setStadiumInfrastructureLevel(null); 
        ..... & so on
      }
    }
    

The problem with this approach is as the number of properties add up in future. This code needs to be updated too. Also, if the number of properties of an object is large. I need to keep setting null here, that many times.

  1. Second approach is create a new Match object within the loop & just set the 3 required values to it.

    List<Match> matchesToday = matchInvService.fetchMatchByDate(today);
    List<Match> responseList = new ArrayList<Match>();  
    
    for (Match stats : matchesToday) {
     if (stats != null) {
       Match tmpMatch = new Match();
       match.setProperty1(stats.getProperty1());
      }
     responseList.add(tmpMatch); 
    }
    
     return responseList;
    

This approach creates additional Match objects every time the loop runs. Also, the creation of objects spike up if that particular method is called too often. Though the objects will be garbage collected, I ain't sure if this is an optimal way.

Need your suggestion guys. Is this a trade off between writing more code vs saving memory? What would be the best approach to tackle this?

underdog
  • 4,447
  • 9
  • 44
  • 89

5 Answers5

3

The object Match has say 15 properties & I need only 3 properties on the UI. I do not want the user to see the other properties of the object.

Setting all fields to null is indeed cumbersome and error prone.
So I would avoid the first way.

The second approach seems to go in a better direction.
But you should not be afraid to map objects to other objects because clients need to see a particular view of them.
Simple mapping operations for a "reasonable" list size is cheap. And I suppose that you will not display millions of rows in the UI, so the size should be reasonable.
Otherwise you should re-think the whole UI design by considering the paging concept.

I would use a third option : create a class declaring the 3 properties the client needs to know and map Match to this class. It makes things much clearer.

List<Match> matchesToday = matchInvService.fetchMatchByDate(today);
List<MatchDTO> responseList = new ArrayList<Match>();  

for (Match stats : matchesToday) {
 if (stats != null) {
    MatchDTO match = new MatchDTO(stats);
    responseList.add(match); 
  } 
}

return responseList;

Where MatchDTO(Match) is a constructor that copies from Match instance the 3 needed fields :

public MatchDTO(Match match){
  this.foo = match.getFoo();
  this.bar = match.getBar();
  this.fooBar = match.getFooBar();
}

or in Java 8 :

List<MatchDTO> responseList =   
    matchInvService.fetchMatchByDate(today)
                   .stream()
                   .filter(Objects::nonNull)
                   .map(MatchDTO::new)
                   .collect(Collectors.toList);
davidxxx
  • 125,838
  • 23
  • 214
  • 215
1

You can create a new transfer object (a simple POJO) in which you can define the fields you want to send over to the UI.

This way you'll be decoupling your response from the actual database entity. So in that sense, your service layer will retrieve the matches based on the various conditions you have and store them in a list.

You can then go ahead and stream the list mapping them to the new transfer object (the POJO mentioned before) using either a Function or an implementation of Spring's Converter interface.

Thus when done, your response will consist of a list of transfer objects with the fields you want to send over to the UI.

akortex
  • 5,067
  • 2
  • 25
  • 57
1

Service should answer only with required details. Java's GC deals very well with deletion of small object if they no longer required. So I would go ahead with creating small objects representing required state and passing them in response. e.g.

return matchesToday.stream().map(MatchInfoResponse::new).collect(Collectors.toList());
udalmik
  • 7,838
  • 26
  • 40
1

It is always a good practice to constrain your query to only ask for the properties that you need.

So instead of matchInvService.fetchMatchByDate(today); returning the whole Match you could implement a native query for example. Also, it is a good idea instead of returning the entities to return DTOs.

A small example using the SqlResultSetMapping annotation follows:

MatchDTO match = (MatchDTO) em.createNativeQuery("select m.property1, m.property2, m.property3 from match where m.date=aDate", "MatchDTOMapping").getSingleResult();

having

class MatchDTO {

    private String property1
    private String property2;
    private String property3;

  //omit other attributes 

   public MatchDTO(String property1, String property2, String property3) {
      this.property1 = property1;
      this.property2 = property2;
      this.property3 = property3;

   }

}

annotated with

@SqlResultSetMapping(name="MatchDTOMapping",
    classes="@ConstructorResult(
    targetClass= MatchDTO.class,
    columns = {@ColumnResult(name="property1"),
               @ColumnResult(name="property2"),
               @ColumnResult(name="property3")}))

Here you can also find solutions using native and JPQL queries.

Eirini Graonidou
  • 1,506
  • 16
  • 24
1

If the original list is no longer used.You can set it to null and it will be reclaimed sooner or later.I think it's meaningless to consider the memory.