Perform repeating check in spring controller - spring

I am building a website that works with a "Ticket" entity. This entity has an id and various operations are performed on the ticket based on the given ID. I have to handle the cases where this id leads to a non-existing ticket, and so I just take the ID at the start of pretty much every controller method and check if I find this object in the repository.
This seems very repeating and not like good style to me and I was wondering if there was any more elegant way to do this. This is how my controller looks at the present time:
public class TicketController {
//Services and repositories are initialized on top
#PostMapping("/ticket/reassign/{id}")
public String reassign(#PathVariable int id, TicketReassignForm reassignForm) {
Optional<Ticket> ticket = ticketRepository.findById(id);
if (!ticket.isPresent()) {
eventMessageService.addMessage(EventMessageBag.Type.ERROR, "Ticket wurde nicht gefunden", "Das gewünschte Ticket wurde nicht gefunden.");
return "redirect:/ticket";
} //these lines are present at the start of almost all methods in the controller
//method does stuff with the ticket...
}
#PostMapping("/ticket/removelabel/{ticketId}/{labelId}")
public String removeLabel(#PathVariable int ticketId, #PathVariable int labelId) {
Optional<Ticket> ticket = ticketRepository.findById(ticketId);
if (!ticket.isPresent()) {
eventMessageService.addMessage(EventMessageBag.Type.ERROR, "Ticket wurde nicht gefunden", "Das gewünschte Ticket wurde nicht gefunden.");
return "redirect:/ticket";
} //Again, code lines are repeated...
//Method does stuff...
}
}
I wish to put these lines in a separate method or so, repeating this check in the current manner does not seem optimal to me. How can I improve this?

Related

Spring Mongo Aggregation that doesn't return duplicates values

I'm working on Spring while using Mongo as database. I have some collections and elements inside it. I'm trying to create a function that will return a random element from collection on every call but not return same element twice.
I have this in my repository class:
#Aggregation(pipeline = {"{'$match':{'typeOfAdventureHolidays':'summerCamps'}}", "
{$sample:{size:1}}"})
AggregationResults<AdventureHolidays> randomSummerCamps();
This return me a random value but also show me same value twice, while I want to avoid that.
I tried to search for some answers but I just founded a couple of ways to prevent it but to not show duplicate elements, no to not return same element twice.
So my code is like this.
Repository
#Aggregation(pipeline = {"{'$match':{'typeOfAdventureHolidays':'summerCamps'}}", "
{$sample:{size:1}}"})
AggregationResults<AdventureHolidays> randomSummerCamps();
ServiceImpl
#Override
public List<AdventureHolidays> getRandomSummerCamps() {
return Collections.singletonList(adventureHolidaysRepository.randomSummerCamps().
getMappedResults().stream().findFirst().orElse(null));
}
Controller
#GetMapping("/getRandomSummerCamps")
public String getRandomSummerCamps(Model model) {
model.addAttribute("randomSummerCamps",
adventureHolidaysService.getRandomSummerCamps());
return "randomSummerCamps";
}
If I need to provide something else I'm here, I tried to find something that will be useful but no success

Get current classifications from custom classifier

I'm trying to create a classifier VS extension to colorize "TODO" comments. For that, in my IClassifier.GetClassificationSpans method I want to get the current classification spans, and only process those classified as "comment".
In my classifier provider I added an IClassifierAggregatorService field, and used its GetClassifier method to pass the result to my classifier, which can use it to get the classifications. However, this generates a StackOverflowException, since my GetClassifier method is called again and again in a loop:
using System.ComponentModel.Composition;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Classification;
using Microsoft.VisualStudio.Utilities;
namespace TestTasksClassifier
{
[Export(typeof(IClassifierProvider))]
[ContentType("code")]
internal class EditorClassifier1Provider : IClassifierProvider
{
[Import] private IClassificationTypeRegistryService classificationRegistry;
[Import] private IClassifierAggregatorService aggregatorService;
public IClassifier GetClassifier(ITextBuffer buffer)
{
return buffer.Properties.GetOrCreateSingletonProperty<EditorClassifier1>(creator: () =>
new EditorClassifier1(classificationRegistry, aggregatorService.GetClassifier(buffer)));
}
}
}
To solve the StackOverflowException, in GetClassifier I've ended using ITextBuffer.Properties to store my classifier instance, and if it already exists I just return a null classifier to stop the loop. It works in my limited tests, but I have no idea whether this is a valid and safe approach:
public IClassifier GetClassifier(ITextBuffer buffer)
{
if (buffer.Properties.TryGetProperty<EditorClassifier1>(typeof(EditorClassifier1), out var _))
{
return null;
}
else
{
EditorClassifier1 editorClassifier1 = new EditorClassifier1(classificationRegistry);
buffer.Properties.AddProperty(typeof(EditorClassifier1), editorClassifier1);
// Now I can call "aggregatorService.GetClassifier", since "editorClassifier1" is already added to "buffer.Properties",
// and this method will return null when called again.
editorClassifier1.Classifier = aggregatorService.GetClassifier(buffer);
return editorClassifier1;
}
}
What would be the best approach to retrieve the current classifications from my custom classifier?

How can I have two return types in one controller returning Collection of Class A or Object of Class B

I am trying to follow Rest Principles, so I have two rest controllers
with a base URL localhost:8088/trucks.
First, I have to get all trucks:
#GetMapping(value = "/trucks")
public final Collection<TruckDto> getAllTrucks() {
LOGGER.debug("test: getAllTrucks()");
Collection<Truck> trucks = truckService.getAllTrucks();
return mappingService.map(trucks, TruckDto.class);
}
Note, my issue also has to do with the fact that I have different classes I am returning for truckById and truckByTruckCode.
And I have 'get truck by ID' service:
#GetMapping(value = "/trucks/{truckId:[0-9]+}")
#ResponseStatus(HttpStatus.FOUND)
#ResponseBody
public final TruckDto getTruckId(#PathVariable(value = "truckId") final Integer truckId) {
LOGGER.debug("test: truckId({})", truckId);
Truck truck = truckService.getTruckById(truckId);
return mappingService.map(truck, TruckDto.class);
}
Now I have a get by truckCode that works but it doesnt follow the rest principle , which is something like , there should be only one base url and all others build from it , here it is
#ResponseStatus(HttpStatus.OK)
#ResponseBody
#GetMapping(value = "/trucks/{truckCode:[0-9]*[a-zA-Z][a-zA-Z0-9]*}")
public final TruckWithAvgPetrolDto getTruckByTruckCode (#PathVariable(value = "truckCode")
final String truckCode) {
LOGGER.debug("getTruckByTruckCode()");
TruckWithAvgDto truck = truckService.getTruckByTruckCode(truckCode);
return mappingService.map(truck, TruckWithAvgPetrolDto.class);
}
Now it works but I think it should be an optional param there for it should be in one method. So maybe I can have some sort of optional return type because I have two different services, methods to return in both situations.
Because get by id just gets truck detail, but get by trukCode performs a left join and gets truck average consumption of petrol from an order table so I have two different DTOs for get by id and get by truckCode.
My questions are how can I get something like one method say getBY(param) if I put a number it should get by id and return TruckDto but if I put a code like BY788 it should get by code and return a TruckWithAvgPetrolDto. Is that's possible?
This is a solution that works but i will need verification that it is ok to do such in rest or it is bad practice
#GetMapping("/trucks/{value}")
public ResponseEntity<?> getTruckByIdOrCode(#PathVariable(value = "value" )String value) {
if (value.matches("[0-9]*[a-zA-Z][a-zA-Z0-9]*")) {
TruckWithAvgDto list = truckService.getTruckByTruckCode(value);
return new ResponseEntity<TruckWithAvgDto>(list, HttpStatus.FOUND);
}else {
Truck truck = truckService.getTruckById(Integer.parseInt(value));
return new ResponseEntity<Truck>(truck,HttpStatus.FOUND);
}
}

Querying single database row using rxjava2

I am using rxjava2 for the first time on an Android project, and am doing SQL queries on a background thread.
However I am having trouble figuring out the best way to do a simple SQL query, and being able to handle the case where the record may or may not exist. Here is the code I am using:
public Observable<Record> createRecordObservable(int id) {
Callable<Record> callback = new Callable<Record>() {
#Override
public Record call() throws Exception {
// do the actual sql stuff, e.g.
// select * from Record where id = ?
return record;
}
};
return Observable.fromCallable(callback).subscribeOn(Schedulers.computation());
}
This works well when there is a record present. But in the case of a non-existent record matching the id, it treats it like an error. Apparently this is because rxjava2 doesn't allow the Callable to return a null.
Obviously I don't really want this. An error should be only if the database failed or something, whereas a empty result is perfectly valid. I read somewhere that one possible solution is wrapping Record in a Java 8 Optional, but my project is not Java 8, and anyway that solution seems a bit ugly.
This is surely such a common, everyday task that I'm sure there must be a simple and easy solution, but I couldn't find one so far. What is the recommended pattern to use here?
Your use case seems appropriate for the RxJava2 new Observable type Maybe, which emit 1 or 0 items.
Maybe.fromCallable will treat returned null as no items emitted.
You can see this discussion regarding nulls with RxJava2, I guess that there is no many choices but using Optional alike in other cases where you need nulls/empty values.
Thanks to #yosriz, I have it working with Maybe. Since I can't put code in comments, I'll post a complete answer here:
Instead of Observable, use Maybe like this:
public Maybe<Record> lookupRecord(int id) {
Callable<Record> callback = new Callable<Record>() {
#Override
public Record call() throws Exception {
// do the actual sql stuff, e.g.
// select * from Record where id = ?
return record;
}
};
return Maybe.fromCallable(callback).subscribeOn(Schedulers.computation());
}
The good thing is the returned record is allowed to be null. To detect which situation occurred in the subscriber, the code is like this:
lookupRecord(id)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<Record>() {
#Override
public void accept(Record r) {
// record was loaded OK
}
}, new Consumer<Throwable>() {
#Override
public void accept(Throwable throwable) {
// there was an error
}
}, new Action() {
#Override
public void run() {
// there was an empty result
}
});

Mark ItemViewModel as dirty explicitly

I have address editor fragment, after user edit address I save changed model values to a database
fun saveAddressTable(tableViewEditModel: TableViewEditModel<Client>) {
tableViewEditModel.items.asSequence()
.filter { it.value.isDirty }
.forEach {
//do stuff }
}
Some adressess have obvious mistakes I can fix programmatically, however model is not marked as dirty after I change it.
For example,
fun autoEditAddressTable(tableViewEditModel: TableViewEditModel<Client>) {
tableViewEditModel.items.asSequence()
.forEach {
val client = it.value.item
client.localProperty.value = client.local.replace(",{2,}".toRegex(), ",")
}
}
Changes reflected in the UI, but model itself is not dirty. I've found markDirty() property method, but it doesn't help much. As model is not marked dirty, it fails filter criteria on save.
center = tableview ( controller.clients ) {
column("Local Address", Client::localProperty)
.prefWidth(400.0)
.makeEditable()
bindSelected(controller.clientModel)
enableDirtyTracking()
tableViewEditModel = editModel
}
Isn't TableViewEditModel expected to trace all model alteration? If client edits Local Address column manually, model becomes dirty.

Resources