Last active
September 11, 2015 17:32
-
-
Save dwelch2344/bcba54f73c3f18fcc818 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class ExampleController { | |
@Inject | |
private StepRepo stepRepo; | |
@Inject | |
private StepChildRepo childRepo; | |
@RequestMapping(value = "/{stepId}/options/", method = RequestMethod.PUT, consumes = MediaType.APPLICATION_JSON_VALUE) | |
public @ResponseBody Object putOptions(@RequestBody OptionList beans, @PathVariable Long stepId){ | |
Assert.notNull(beans); | |
Step parent = stepRepo.findOne(stepId); | |
Assert.notNull(parent, "Could not find parent step by id " + stepId); | |
MergeUtils.merge(parent.getOptions(), beans) | |
.create(b -> { | |
Step step = stepRepo.findOne(b.getStep()); | |
Assert.notNull(step, "Could not find option-step by id " + b.getStep()); | |
StepOption option = new StepOption(b.getOption(), step); | |
option = parent.addOption(option); | |
option = optionRepo.saveAndFlush(option); | |
return Optional.of(option); | |
}) | |
.update((option, b) -> { | |
option.setOption(b.getOption()); | |
optionRepo.saveAndFlush(option); | |
return Optional.of(option); | |
}) | |
.delete(option -> { | |
parent.removeOption(option); | |
optionRepo.delete(option); | |
// return empty so our results don't contain the deleted ones | |
return Optional.empty(); | |
}) | |
.execute(); | |
Step saved = stepRepo.findOne(stepId); | |
StepFullProjection projection = projectionFactory.createProjection(saved, StepFullProjection.class); | |
return ResponseEntity.ok(projection); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import com.google.common.collect.Lists; | |
import org.apache.commons.lang3.tuple.MutablePair; | |
import org.apache.commons.lang3.tuple.Pair; | |
import org.springframework.hateoas.Identifiable; | |
import org.springframework.util.LinkedMultiValueMap; | |
import org.springframework.util.MultiValueMap; | |
import java.io.Serializable; | |
import java.util.*; | |
import java.util.function.BiFunction; | |
import java.util.function.Consumer; | |
import java.util.function.Function; | |
import java.util.stream.Collectors; | |
import java.util.stream.Stream; | |
/** | |
* Created by dave on 9/10/15. | |
*/ | |
public class MergeUtils { | |
public static < | |
E extends Identifiable<K>, | |
B extends Identifiable<K>, | |
K extends Serializable | |
> | |
MergeProcessor<E, B, K> merge(Collection<E> entities, Collection<B> beans){ | |
return diff(entities, beans).processor(); | |
} | |
public static < | |
E extends Identifiable<K>, | |
B extends Identifiable<K>, | |
K extends Serializable | |
> | |
MergeResult<E, B, K> diff(Collection<E> entities, Collection<B> beans){ | |
Map<K, B> modified = beans.stream() | |
.filter(b -> b.getId() != null) | |
.collect(Collectors.toMap( | |
b -> b.getId(), b -> b)); | |
Set<K> modifiedIds = modified.keySet(); | |
List<K> removedIds = entities.stream() | |
.filter(e -> !modifiedIds.contains(e.getId())) | |
.map(e -> e.getId()) | |
.collect(Collectors.toList()); | |
MergeResult<E, B, K> result = new MergeResult(); | |
entities.forEach(e -> { | |
K id = e.getId(); | |
if (modifiedIds.contains(id)) { | |
result.modified.add(id, new MutablePair<>(e, modified.get(id))); | |
} else if (removedIds.contains(id)) { | |
result.removed.add(e); | |
} else { | |
throw new IllegalStateException("Could not determine the status for entity " + id); | |
} | |
}); | |
beans.stream() | |
.filter(b -> b.getId() == null) | |
.forEach(result.created::add); | |
return result; | |
} | |
public static class MergeResult<E, B, K> { | |
private List<B> created = Lists.newArrayList(); | |
private MultiValueMap<K, Pair<E, B>> modified = new LinkedMultiValueMap<>(); | |
private List<E> removed = Lists.newArrayList(); | |
public List<B> getCreated() { | |
return Lists.newArrayList(created); | |
} | |
public MultiValueMap<K, Pair<E, B>> getModified() { | |
return new LinkedMultiValueMap<>(modified); | |
} | |
public List<E> getRemoved() { | |
return Lists.newArrayList(removed); | |
} | |
public MergeProcessor<E, B, K> processor(){ | |
return new MergeProcessor(this); | |
} | |
} | |
public static class MergeProcessor<E, B, K> { | |
private final MergeResult<E, B, K> merge; | |
private Function<B, Optional<E>> create; | |
private BiFunction<E, B, Optional<E>> update; | |
private Function<E, Optional<E>> delete; | |
public <E, B, K> MergeProcessor(MergeResult merge) { | |
this.merge = merge; | |
} | |
public MergeProcessor<E, B, K> create(Function<B, Optional<E>> create){ | |
this.create = create; | |
return this; | |
} | |
public MergeProcessor<E, B, K> update(BiFunction<E, B, Optional<E>> update){ | |
this.update = update; | |
return this; | |
} | |
public MergeProcessor<E, B, K> delete(Function<E, Optional<E>> delete){ | |
this.delete = delete; | |
return this; | |
} | |
public Stream<E> execute(){ | |
List<E> result = Lists.newArrayList(); | |
if( create != null ) { | |
merge.created.stream() | |
.map(create) | |
.forEach( unwrapOptional(result) ); | |
} | |
if( update != null ) { | |
merge.modified.values().stream() | |
.forEach(l -> l.stream() | |
.map(p -> update.apply(p.getLeft(), p.getRight()) ) | |
.forEach( unwrapOptional(result) ) | |
); | |
} | |
if( delete != null ){ | |
merge.removed.stream() | |
.map(delete) | |
.forEach( unwrapOptional(result) ); | |
} | |
return result.stream(); | |
} | |
private <T> Consumer<Optional<T>> unwrapOptional(Collection<T> results){ | |
return (Optional<T> o) -> { | |
if( o != null ){ | |
o.ifPresent(results::add); | |
} | |
}; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment