mercredi 1 juillet 2015

Reusing part of Stream mapping and filtering to compose two different results

I'd like to know if there is a good way of reusing a common stream operation that varies in the end for different outputs. The example bellow is exactly what I'm trying to compact into a one-step operation:

public static DepartmentInfo extractDepartmentInfo(BaselinePolicy resource) throws ResourceProcessorError {
    Function<Exception, Exception> rpe = e -> new ResourceProcessorError(e.getMessage());
    List<String> parents = 
            Objects.requireNonNull(
                Exceptions.trying(
                    () -> Arrays.asList(Exceptions.dangerous(resource::getParentIds).expecting(CMException.class).throwing(rpe))
                                .stream()
                                .map(cId -> Exceptions.dangerous(cId, resource.getCMServer()::getPolicy).expecting(CMException.class).throwing(rpe))
                                .filter(policy -> PagePolicy.class.isAssignableFrom(policy.getClass()))
                                .map(PagePolicy.class::cast)
                                .filter(page -> Exceptions.dangerous(page,
                                                                     p -> Boolean.valueOf(p.getComponentNotNull(ComponentConstants.POLOPOLY_CLIENT, 
                                                                                                                ComponentConstants.IS_HOME_DEPARTMENT,
                                                                                                                Boolean.FALSE.toString())).booleanValue())
                                                          .expecting(CMException.class).throwing(rpe))
                                .map(page -> Exceptions.dangerous(page, p -> p.getExternalId().getExternalId()).expecting(CMException.class).throwing(rpe)), ResourceProcessorError.class)
                                .collect(Collectors.toList()));
    String externalId = parents.get(parents.size()-1).toString();
    List<String> list = 
        Objects.requireNonNull(
                Exceptions.trying(
                    () -> Arrays.asList(Exceptions.dangerous(resource::getParentIds).expecting(CMException.class).throwing(rpe))
                                .stream()
                                .map(cId -> Exceptions.dangerous(cId, resource.getCMServer()::getPolicy).expecting(CMException.class).throwing(rpe))
                                .filter(policy -> PagePolicy.class.isAssignableFrom(policy.getClass()))
                                .map(PagePolicy.class::cast)
                                .map(page -> 
                                    Exceptions.dangerous(page, 
                                            p -> p.getChildPolicy(PATH_SEGMENT) != null && 
                                                 StringUtils.hasLength(SingleValued.class.cast(p.getChildPolicy(PATH_SEGMENT)).getValue())? 
                                                 SingleValued.class.cast(p.getChildPolicy(PATH_SEGMENT)).getValue(): p.getName()).expecting(CMException.class).throwing(rpe))
                                .filter(val -> val != null && !val.isEmpty()), ResourceProcessorError.class)
                                .collect(Collectors.toList()));
    if(list.size() > 3) {
        list = list.subList(list.size() - 3, list.size()-1);
    }
    switch(list.size()) {
        case 0: {
            throw new ResourceProcessorError("br.com.oesp.XMLRender.error.noProduct");
        }
        case 1: {
            return DepartmentInfo.withProduct(list.get(0), externalId);
        }
        case 2: {
            return DepartmentInfo.withProduct(list.get(0), externalId).withDepartment(list.get(1));
        }
        default: {
            return DepartmentInfo.withProduct(list.get(0), externalId).withDepartment(list.get(1)).withSubDepartment(list.get(2));
        }
    }
}

Notice that the first step is repeated for both:

List<String> parents = 
        Objects.requireNonNull(
            Exceptions.trying(
                () -> Arrays.asList(Exceptions.dangerous(resource::getParentIds).expecting(CMException.class).throwing(rpe))
                            .stream()
                            .map(cId -> Exceptions.dangerous(cId, resource.getCMServer()::getPolicy).expecting(CMException.class).throwing(rpe))
                            .filter(policy -> PagePolicy.class.isAssignableFrom(policy.getClass()))
                            .map(PagePolicy.class::cast)

It's not only a problem for reading but specially because I'm redoing a heavy operation twice, meanwhile in a more imperative way I'd do it once.

Aucun commentaire:

Enregistrer un commentaire