What's the best way to read properties from the GWT host page?
I'm trying to find a simple way to embed properties into the host page and access them from Java.
It seems like Dictionary is the recommended way to go, but it's somewhat fragile in that your dictionary must exist in the host page, or it errors with MissingResourceException. Similarly, Dictionary.get() will throw a resource error if the key you request does not exist.
I'm writing a library, and I'd prefer a more robust solution that won't error out if the user doesn't specify the dictionary or key. Should I just catch exceptions thrown by the Dictionary and return null? Is there a more robust way to do this?
EDIT: at the moment, I'm using the following:
protected Dictionary dict;
public ClientConfiguration(String configName)
{
try
{
dict = Dictionary.getDictionary(configName);
} catch (MissingResourceException e)
{
dict = null;
}
}
public String getString(String key)
{
return dict == null ? null : dict.keySet().contains(key) ? dict.get(key) : null;
}
I would say, your solution is very robust already. It's absolutely ok to catch - without rethrowing -
a specific Exception (MissingResourceException)
which you expect to occur (the resource could be missing),
and which will only occur under the circumstances you expect (it would be bad to catch a NullPointerException, because there can be many reasons for that Exception).
You could even change your getString() method a little bit:
public String getString(String key) {
try {
return dict == null ? null : dict.get(key);
} catch (MissingResourceException e) {
return null;
}
}
This should make the method almost twice as fast, because you save the extra call to dict.keySet().contains(key), which takes approximately as long as dict.get(key).
Related
I am trying to find the best approach for default and error handling with reactive.
This is a working code.
public Mono<ServerResponse> retrieveById(ServerRequest request) {
final String id = request.pathVariable("ID");
return context.retrieveUser().flatMap(usr -> {
return repository.findByApptId(Long.parseLong(id), usr.getOrgId()).flatMap(appt -> {
return ServerResponse.ok().contentType(APPLICATION_JSON).bodyValue(appt);
});
});
}
I am trying to add default and error handling.
For default,
return context.retrieveUser().flatMap(usr -> {
return repository.findByApptId(Long.parseLong(apptId), usr.getOrgId()).flatMap(appt -> {
return ServerResponse.ok().contentType(APPLICATION_JSON).bodyValue(appt);
}).defaultIfEmpty(ServerResponse.notFound().build());
The above default add gives error.
The method defaultIfEmpty(ServerResponse) in the type
Mono is not applicable for the arguments
(Mono)
Same error with onErrorReturn as well.
Mono#defaultIfEmpty takes an item T and returns a Mono<T>. Which means that if you give it a String it will return a Mono<String>.
You are giving it ServerResponse.notFound().build() which returns a Mono<ServerResponse> which won’t work since it would give Mono<Mono<ServerResponse>>.
What you are looking for is Mono#switchIfEmpty which switches producer (Mono) to another producer if the previous one turned out empty.
Basically what I am trying to achieve is to call a second repository (a ReactiveCrudRepository) or throw an exception, depending on the result of a call to a first repository.
My original idea looks like this:
/** Reactive with blocking code */
public Flux<SecondThing> getThings(String firstThingName) {
FirstThing firstThing = firstRepo
.findByName(firstThingName)
// Warning: "Inappropriate blocking method call"
.blockOptional() // this fails in test-context
.orElseThrow(() -> new FirstThingNotFound(firstThingName));
return secondRepo.findAllByFirstThingId(firstThing.getId());
}
Which would correspond to the following non-reactive approach:
/** Non-reactive */
public List<SecondThing> getThings(String firstThingName) {
FirstThing firstThing = firstRepo
.findByName(firstThingName)
.orElseThrow(() -> new FirstThingNotFound(firstThingName));
return secondRepo.findAllByFirstThingId(firstThing.getId());
}
I haven't found a way to do this in a reactive non-blocking way. All I need is to throw an error if an empty Mono comes out of the first call, and continue the pipeline if not empty; but I could not seem to use onErrorStop or doOnError correctly here, and map does not help as it skips the empty Mono.
What I have is a workaround if I use id instead of name, but I'm not quite satisfied with it as it shows a different behaviour in the case where is an instance of FirstThing but no SecondThing linked to it:
/** Reactive workaround 1 */
public Flux<SecondThing> getThings(Long firstThingId) {
return secondRepo
.findAllByFirstThingId(firstThingId)
.switchIfEmpty(
Flux.error(() -> new FirstThingNotFound(firstThingName))
);
}
Another workaround I've found is the following, that replaces the empty Mono with a null value, but it doesn't look right and throws a warning too:
/** Reactive workaround 2 */
public Flux<SecondThing> getThings(String firstThingName) {
return firstRepo
.findByName(firstThingName)
// Warning: "Passing 'null' argument to parameter annotated as #NotNull"
.defaultIfEmpty(null)
.flatMapMany(
firstThing -> secondRepo.findAllByFirstThingId(firstThing.getId()
)
.onErrorMap(
NullPointerException.class, e -> new FirstThingNotFound(firstThingName)
);
}
What is the correct way to chain the calls to both repositories so that the presence or absence of a FirstThing with the requested firstThingName conditions the call to the second repo?
I found a solution so simple, that I could be ashamed not to have found it earlier:
public Flux<SecondThing> getThings(String firstThingName) {
return firstRepo
.findByName(firstThingName)
.switchIfEmpty(Mono.error(() -> new FirstThingNotFound(firstThingName)))
.flatMapMany(
firstThing -> secondRepo.findAllByFirstThingId(firstThing.getId()
);
}
The trick is that switchIfEmpty does not force you to pick a "valid" replacement value, so it is possible to use a Mono.error to propagate the right exception directly.
I have an ASP.NET Core 2.0 Site that has a scaffolded controller built directly from a simple model and simple context. I seeded the data by simply checking for the number of records in the GET method and if 0, then I added 100 records. GET is retrieving records as I would expect repeatedly.
I'm using the inmemory database provider.
services.AddDbContext<MyDbContext>
(opt => opt.UseInMemoryDatabase("CodeCampInMemoryDb"));
When I do a PUT with a record that I know existed in my GET, I get a concurrency error as shown at the bottom of this post. I've not used this method of changing the EntityState of a record I created myself, so I'm not sure how this was suppose to work in the first place, but clearly now it is not working.
Maybe it has something to do with a transaction being processed on the inmemory database? I'm not sure how to avoid that if that is the problem.
// PUT: api/Sessions/5
[HttpPut("{id}")]
public async Task<IActionResult> PutSessionRec([FromRoute] int id, [FromBody] SessionRec sessionRec)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
if (id != sessionRec.Id)
{
return BadRequest();
}
_context.Entry(sessionRec).State = EntityState.Modified;
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException xx)
{
if (!SessionRecExists(id))
{
return NotFound();
}
else
{
throw;
}
}
return NoContent();
}
Microsoft.EntityFrameworkCore.DbUpdateConcurrencyException: Attempted to update or delete an entity that does not exist in the store.
at Microsoft.EntityFrameworkCore.Storage.Internal.InMemoryTable`1.Update(IUpdateEntry entry)
at Microsoft.EntityFrameworkCore.Storage.Internal.InMemoryStore.ExecuteTransaction
If you marked a property as a Timestamp and don't provide it, you will get this exception every time. You either need to load the entity with the latest Timestamp and update that (not ideal) or you have to send the Timestamp down to the client and have the client send it back up (correct way). However, if you are using an older version of JSON serialization, you have to convert the byte[] to base 64 and then convert it back.
I have a very strange bug and I don't know what is going on.
I have an endpoints like this:
private void init() {
if (ioConfigurationDAO == null) {
ioConfigurationDAO = new IOConfigurationDAO();
ioConfigurationDAO.init();
}
property = new AigatewayProperty();
}
#GET
#Path("/{id : \\d+}")
#Produces(MediaType.APPLICATION_JSON)
public Response getIoConfiguration(#PathParam("id") Integer id) {
init();
if (!ChannelName.isValidChannel(id)) {
return Response.status(Response.Status.NOT_FOUND).build();
}
IOConfiguration ioConfig = ioConfigurationDAO.findIOConfiguration("CH" + id);
System.out.println(ioConfig.getConversionType());
// close();
return Response.status(Response.Status.OK).entity(ioConfig).build();
}
When I am making request to this url: http://localhost:8080/aigateway/rest/ioconfiguration/3
Some time, I get a correct response:
{"ioConfigurationId":"CH3","active":true,"name":"1","conversionType":"Linear","mInfo":0.32,"bInfo":0.55,"voltageDivide":"/4","sampleRange":"24
Bits","samplePeriod":10,"storeRaw":false,"storeConverted":false,"defaultGraph":"Line","title":"","unit":"","rangeLowerbound":0,"rangeUpperbound":100,"code":"function
conversion_CH3 (input) {\n\treturn input;\n}"}
Sometimes, I get wrong response with null values:
{"ioConfigurationId":"CH3","active":null,"name":null,"conversionType":null,"mInfo":null,"bInfo":null,"voltageDivide":null,"sampleRange":null,"samplePeriod":null,"storeRaw":null,"storeConverted":null,"defaultGraph":null,"title":null,"unit":null,"rangeLowerbound":null,"rangeUpperbound":null,"code":null}
I don't know what is going on.
One thing to mention is that:
I have to manually initiate my entity manager becuase my EJB annotations doesn't work, and I am not closing my connection to the database since I don't know when the applicaton will end. I don't know if this is the reason that cause this problem.
Someone please help me, if you need more information, I am willing to share.
Thanks!
I solved this problem by using EJB properly. The only reason I can think that is causing this problem is because I never close the my entity manager, so the next time when I am trying to create a new one, there is some problem going on and that's why I am getting null values sometimes.
I have created a sample application in Silverlight with RIA services. I am using entity framework for CRUD operation but it does not work for INSERT Operation with following Exception, "Submit operation failed validation. Please inspect Entity.ValidationErrors for each entity in EntitiesInError for more information." I have not apply any validation but don't know how the error occurs.
I have tested that when I create an object of DB entity and assign values to it and then save by calling object.SaveChages(), it works fine. But its default method does not work. Any help is appreciated.
Thanks
The SubmitOperation callback has an EntitiesInError property which you can use to iterate thru the entities. That's the way of getting the "real" error.
Here's the method I have to show the user what went wrong...
public static bool WasSubmittedOK(SubmitOperation so, string errorMessageHeader, out string errorMessage)
{
errorMessage = string.Empty;
if (!so.HasError)
return true;
so.MarkErrorAsHandled();
errorMessage = "An unknown error has occurred";
if (so.EntitiesInError.Count() > 0)
{
StringBuilder builder = new StringBuilder();
builder.AppendFormat("{0}\r\n", errorMessageHeader);
foreach (Entity item in so.EntitiesInError)
{
#if DEBUG
builder.AppendFormat("\r\nFor {0}", item.GetType());
#endif
foreach (ValidationResult error in item.ValidationErrors)
{
builder.AppendFormat("\r\n- {0}", error.ErrorMessage);
Debug.WriteLine(string.Format("Error in {0}:'{1}'", string.Join(",", error.MemberNames.ToArray()), error.ErrorMessage));
}
}
errorMessage = builder.ToString();
}
else if (so.Error != null) { errorMessage = so.Error.Message; }
return false;
}
Are you able to drill into the validation errors? I actually have an article about this coming in December MSDN Magazine Data Points but I bet you don't want to wait, right? :)
Even if you haven't applied any specific validations, there are things like foreign key contsraints that EF will still check. If you can see what the error is that will be ultimately useful in solving your problem. Debug into the exception. See if there is a DbEntityValidationException available...maybe it's in an innerexceptoin. DbEntityValidationException will have one or more EntityValidationErrors. Each of those contains a list of all of the errors found for one instance. That means expanding the EntityValidationErrors items one at a time and looking at the ValidationError items contained within.