0

Is it possible to combine two DAOs into one Service method?

I want to create a generic method which will choose correct DAO based on the input parameter. What for now I came up with is the method which will accept Dao from the outside the service object. But this requires to initialize appropriate Dao in the Controller which is a little bit ugly...

Measurement is just an interface for Temperature.java and Humidity.java entities with separate tables on PostgreSQL.

@Service
public class MeasurementService {

@Autowired
private TemperatureDao temperatureDao;

@Autowired
private HumidityDao humidityDao;

public<T extends PagingAndSortingRepository<Measurement, Long>> void insertMeasurementForUser(String username, List<Measurement> measurements, T dao) {
        dao.saveAll(measurements);
}
}

TemperatureDao.java

@Repository
public interface TemperatureDao extends PagingAndSortingRepository<Temperature, Long> {

    @Query("select u from Temperature u where u.owner = ?1 order by u.id desc")
    List<Temperature> findLatestTemperatureForUser(User user, Pageable pageable);
}

HumidityDao.java

@Repository
public interface HumidityDao extends PagingAndSortingRepository<Humidity, Long> {
    @Query("select u from Humidity u where u.owner = ?1 order by u.id desc")
    List<Humidity> findLatestHumidityForUser(User user, Pageable pageable);
}

Temperature.java

@Entity
@Table(name = "temperature")
public class Temperature implements Measurement {

    @Id
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    private Long id;

    @Column(name = "th1value")
    private Float th1Value;

    @Column(name = "timestamp")
    @NotNull
    private LocalDateTime timestamp;

    @ManyToOne
    @JoinColumn(name = "user_id")
    @NotNull
    private User owner;

    public Temperature() {
    }

    public Temperature(Float th1Value, LocalDateTime timestamp, User owner) {
        this.th1Value = th1Value;
        this.timestamp = timestamp;
        this.owner = owner;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }
    @JsonDeserialize(using = LocalDateTimeDeserializer.class)
    public LocalDateTime getTimestamp() {
        return timestamp;
    }

    @JsonSerialize(using = LocalDateTimeSerializer.class)
    public void setTimestamp(LocalDateTime timestamp) {
        this.timestamp = timestamp;
    }

    @Override
    public User getOwner() {
        return owner;
    }

    @Override
    public void setOwner(User owner) {
        this.owner = owner;
    }
}

Humidity.java

@Entity
@Table(name = "humidity")
public class Humidity {

    @Id
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    private Long id;

    @Column(name = "hum1value")
    private Float hum1Value;

    @Column(name = "timestamp")
    @NotNull
    private LocalDateTime timestamp;

    @ManyToOne
    @JoinColumn(name = "user_id")
    @NotNull
    private User owner;

    public Humidity() {
    }

    public Humidity(Float hum1Value, LocalDateTime timestamp, User owner) {
        this.hum1Value = hum1Value;
        this.timestamp = timestamp;
        this.owner = owner;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    @JsonDeserialize(using = LocalDateTimeDeserializer.class)
    public LocalDateTime getTimestamp() {
        return timestamp;
    }

    @JsonSerialize(using = LocalDateTimeSerializer.class)
    public void setTimestamp(LocalDateTime timestamp) {
        this.timestamp = timestamp;
    }

    public User getOwner() {
        return owner;
    }

    public void setOwner(User owner) {
        this.owner = owner;
    }
}

Any ideas?

tymonz
  • 41
  • 4
  • Share the method – Nicholas K Aug 28 '18 at 16:27
  • I would use a map, but you'll have to define the key properly using which you can invoke the appropriate dao. Creating a map would be done somewhat in the following way- https://stackoverflow.com/questions/20918825/can-spring-autowired-map – pkoli Aug 28 '18 at 16:45
  • Sounds very interesting but I've faced a problem where I had to declare my map. `Map> measurementDaoMap` I believe that this is the only way I can do this and my _@Autowired_ method had to take generics to find proper _@Repository_ `@Autowired public void setMeasurementDaoMap(List> beans) { int i = 0; for(PagingAndSortingRepository b : beans) { measurementDaoMap.put(i++, b); } }` – tymonz Aug 28 '18 at 17:30

2 Answers2

1

You could write a Resolver pattern to return needed dao based on your conditions. You service will use the resolver to get the correct dao.

public HellDao implements BaseDao {
    public void save();
}

public ByeDao implements BaseDao {
    public void save();
}

public DaoResolver {

   @Autowired
   private helloDao;

   @Autowired
   private byeDao;


  public BaseDao resolve(Object input) {
       //based on input return the correct dao
       BaseDao resolvedDao = null;
       switch(input.enum) {
          case Hello:
            resolvedDao = helloDao;
            break;
          case Hello:
            resolvedDao = byeDao;
            break;
          default:
            //decide something for default
       }
   return resolvedDao;
  }
}

public class MyService {

   @Autowired
   private DaoResolver daoResolver;

   public Object doSomething() {
       BaseDao dao = daoResolver.resolve(someObject);
       //you will get HelloDao or ByeDao based on the input
       dao.save();
   }

}
Jayesh
  • 983
  • 6
  • 16
0

You can check for the type of measurements using instanceof so you could do it without generics.

public void insertMeasurementForUser(String username, List<Measurement> measurements) {

       if(measurements.get(0) instanceof Temperature)

       temperatureDao.saveAll(measurements);

       else if(measurements.get(0) instanceof Humidity)

       humidityDao.saveAll(measurements);
}
wdc
  • 2,623
  • 1
  • 28
  • 41