Let's say I have function:
void sayHello(String name, String surname);
and I want to be sure that both parameters are valid. Now I'm doing it this way:
if (name == null)
throw new Exception("Name is invalid");
if (surname == null)
throw new Exception("Surname is invalid");
When I'm invoking it with sayHello(null, null); I'm getting only information about invalid name.
Is there a clean way to be warned about two errors at once? By clean, I mean without two flags (or more in case of more arguments) and many if statements?
The snippets are in Java but I'm rather asking for a generic design solution.
I would suggest to build error message with each validation but throw once i.e. after all validations are done.
Eg:
void someFunction(String param1, String param2, String param3) {
String error = "";
if (invalid(param1)) {
error += "param1 is invalid";
}
if (invalid(param2)) {
error += "param2 is invalid";
}
if (invalid(param3)) {
error += "param3 is invalid";
}
if (!error.equals("")) {
throw new Exception(error);
}
}
Related
i don't know really how to formulate this but what i want is to achieve is the following, read a JSON file from a storage (direct url) but if that JSON file does not exist it should return an empty array.
this is what i got so far (and works)
public object GetFromFile(int Code)
{
string uriPath = "http://mystorage.com/folder/" + Code + ".json";
var allText = (new WebClient()).DownloadString(uriPath);
object jsonObject = JsonConvert.DeserializeObject(allText);
return jsonObject;
}
it returns to me the requested list of codes as a array, now if the code does not exists on the storage, possible, then the webservice should just return and empty array []
desired result:
from file (works):
[{001},{002},{003}]
if file does not exist
[]
//The call to WebClient.DownloadString(string) will throw an exception if the
//uri does not exist, in your case, the json file does not exist
var allText = null;
object jsonObject = null;
try
{
allText = (new WebClient()).DownloadString(uriPath);
jsonObject = JsonConvert.DeserializeObject(allText);
}
catch(WebException ex)
{
jsonObject = new object[0];
}
It seems that you expect that the JSON-file contains a sequence of similar items, from the look of it a sequence of integer numbers.
If you already know that the JSON-file contains this type of objects, it is better to use the overload of DeserializeObject<int>.
IEnumerable<int> ReadNumbersFromWebClient(int Code)
{
string uriPath = "http://mystorage.com/folder/" + Code + ".json";
var downloadedText = DownloadText(uriPath);
return JsonConvert.DeserializeObject<int[]>(allText);
}
string DownloadText(string uriPath)
{
using (var webClient = new WebClient())
{
return webClient.DownloadString(uriPath);
}
}
You said that you wanted to return an empty sequence if the "file does not exist". I assume that you meant: "if the web client says there is no string to download"
I looked at WebClient.DownloadString, and I couldn't find what happens if you use an uriPath that does not exist. Do you get empty string, or an exception?
ICollection<int> ReadNumbersFromWebClient(int Code)
{
// in case of exception: return empty string
try
{
string uriPath = "http://mystorage.com/folder/" + Code + ".json";
var downloadedText = DownloadText(uriPath);
return JsonConvert.DeserializeObject<int[]>(allText);
}
catch (Exception exc) // or use specific exception
{
return new int[];
}
}
It would be neater if you let DownloadText catch the expression. In case of exception return empty string. Experiment what happens if you try to Deserialize an empty string. It will probably be an empty int[]
I have a log() method to avoid try catch statement in forEach() below which was working in other code.
public <T> Consumer<T> log(LogConsumer<T, Throwable> logConsumer)
{
return i -> {
try
{
logConsumer.accept(i);
}
catch (Throwable e)
{
log("e = " + e);
}
};
}
#FunctionalInterface
public interface LogConsumer<T, E extends Throwable> {
void accept(T t) throws E;
}
Now I just want to use log in forEach below but I have the red rippled line in LINE such that
new Task.runJob(job, type))
I have red rippled line under job, type in
"runJob(Job, JobType) in Task cannot be applied to (java.lang.Object, < lambda parameter>)"
Now sure how to fix it to use log in forEach just to avoid
try-catch inside of it.
execute() {
Map<Job, JobType> map = getJobMap();
map.forEach( log((job, type)-> new Taks().runJob(job,type)) ); // LINE: error here
}
class Task {
public String runJob(Job job, JobType type) throws Exception
{
...
return result;
}
}
It happens because you cannot execute functions that throw exceptions using lambda expressions. You have to handle the exception using try-catch block. However, in order for your code to look more readable, create a function, that will handle the exception and return the desired result.
class Task {
public String runJob(Job job, JobType type)
{
try {
...
return result;
} catch (Exception e) {
log.error(e.getMessage());
}
return null;
}
}
In case if you care what will be the result, map it and filter for the result of your function is not null, otherwise, ignore it, but watch logs for any errors.
And then call it like shown below.
Notice: both ways work below, but the second way is more robust because you can handle the scenario when not all jobs were executed without exception.
execute() {
Map<Job, JobType> map = getJobMap();
// First way
map.forEach( log((job, type) -> new Taks().runJob(job,type)) );
// Another way
List<Object> batchResult = map.entrySet().stream()
.map((job, type) -> new Task().runJob(jon, type))
.filter(Objects::nonNull)
.collect(Collectors.toList());
if (batchResult.size() == map.size()) {
// everythings is ok (all operations resulted in non-null result
} else {
// Have to study logs and figure out what went wrong
}
}
public static void insertInboundJive(Map<Id, String> mapCases){
try{
system.debug('Aditya');
Map<Id, String> mapCases1 = new Map<Id, String>();
Map<Id, Integer> mapIncrements = new Map<Id, Integer>();
//List<ICS_Case_Interaction__c> lstCaseInteraction;
if(mapCases != null && mapCases.size() > 0) {
List<ICS_Case_Interaction__c> lstCaseInteraction = [ SELECT Id,case__r.origin FROM ICS_Case_Interaction__c Where case__r.Id =:mapCases.keySet()];
for(ICS_Case_Interaction__c caseInteracts :lstCaseInteraction ){
if(caseInteracts.case__r.Id != null && caseInteracts.case__r.Status == 'New Customer Message'){
system.debug('**AdityaDebug**' +caseInteracts.case__r.Id);
system.debug('**AdityaDebug**' +caseInteracts.case__r.Status);
mapcases1.put(caseInteracts.case__r.Id , TYPE_JIVE_INBOUND);
Integer intIncrement = mapIncrements.get(caseInteracts.case__r.Id);
system.debug('Increment' +intIncrement);
if(intIncrement != null){
intIncrement++;
system.debug('Increment++' +intIncrement);
}
else {
intIncrement = 1;
}
mapIncrements.put(caseInteracts.case__r.Id, intIncrement);
}
}
if(mapCases.size() > 0) {
insertByCaseAsync(mapCases, mapIncrements);
}
}
}
catch(Exception ex){
Core_Log_Entry.logEntryWithException('Case Interaction Metrics', 'CaseInteraction','insertInboundEmail', 'Error', null, null, ex);
}
}
This is my Method in the class.I am trying to call the apex method in the trigger.but its throwing the error.Could you please help me and try to reach out the best.
The error which I am getting was
line 188, col 106. Method does not exist or incorrect signature: void insertInboundJive(List) from the type ICS_Case_Interactions_Trigger_Handler
if(trigger.isUpdate) {
if(Label.ICS_Case_Interaction_Metrics.equals('1')) {ICS_Case_Interactions_Trigger_Handler.insertInboundJive(trigger.new);}
}
You are trying to pass the wrong parameters. In the method you have defined that when called you need to pass a Map where the values are String however you are passing Trigger.new which is a list of Objects. My approach is to handle the mapping in the trigger and then manipulate data in the controller:
In this case you can do the below to pass the records and get the string of data you want in the controller.. or do it in the trigger so you don't change the controller.
Map<Id,Contact> map = new Map<Id,ICS_Case_Interaction__c>(); // new map
for(ICS_Case_Interaction__c con :trigger.new){
map.put(con.Id, con); // enter the records you need for the method
}
if(trigger.isUpdate) {
if(Label.ICS_Case_Interaction_Metrics.equals('1')) {
ICS_Case_Interactions_Trigger_Handler.insertInboundJive(map);
}
}
and in the controller you should have
public static void insertInboundJive(Map<Id, ICS_Case_Interaction__c> mapCases){
}
So I want to use the standard format for error messages. I don't want to specify other than default codes.
Example:
domain.property.minSize.notmet=I like purple {?}.
So I am looping through my errors:
domain.errors.fieldErrors.each {
println g.message(error: it, args: ['bunnies'])
}
This doesn't work correctly because I think the first x arguments are already defined because of the default error message, and that number changes depending on what the error is. How can I specify arguments to the standard error codes without struggling to know what number '?' should be?
So I've gone down this road, hopefully there isn't some way easier option. I am overriding the messageSource bean with my own implementation that simply adds a method:
public class MessageSource extends PluginAwareResourceBundleMessageSource implements GrailsApplicationAware, PluginManagerAware, InitializingBean {
public final String getMessage(MessageSourceResolvable resolvable, Object[] args, Locale locale)
throws NoSuchMessageException {
Object[] arguments;
if (args == null) {
arguments = resolvable.getArguments();
} else {
arguments = args;
}
String[] codes = resolvable.getCodes();
if (codes == null) {
codes = new String[0];
}
for (String code : codes) {
String msg = getMessageInternal(code, arguments, locale);
if (msg != null) {
return msg;
}
}
String defaultMessage = resolvable.getDefaultMessage();
if (defaultMessage != null) {
return renderDefaultMessage(defaultMessage, arguments, locale);
}
if (codes.length > 0) {
String fallback = getDefaultMessage(codes[0]);
if (fallback != null) {
return fallback;
}
}
throw new NoSuchMessageException(codes.length > 0 ? codes[codes.length - 1] : null, locale);
}
}
This is really almost an exact copy of one of the other methods, that I just modified to take in arguments. The problem I am having with this is that it never finds my error message, always falling back to default. msg is always null.
Edit: Just tried it with the standard method and the same is true with msg always being null.
I am having trouble creating generic delete method, not even sure if this possible. I have a delete method which will delete record from db based on entity type and row id value (pk),
that works ok but it needs to know the type in advance. In some cases I can only get object
type using Object.GetType() at runtime (like from viewstate) and that is when trouble starts. Here is my method that works when type is known, is there a way to modify it so that it will use Object.GetType() instead of T ?
public void Delete<T>(long Id) where T : class,new()
{
#region PerformaneMonitor
IDbEntities Db=null;
T item=null;
try
{
Db = this.GetDatabase();
item = new T();
Type itemType = item.GetType();
EntityContainer entityContainer = Db.MetadataWorkspace.GetEntityContainer(Db.DefaultContainerName, DataSpace.CSpace);
var entity = entityContainer.BaseEntitySets.First(b => b.ElementType.Name == itemType.Name);
if (entity.ElementType.KeyMembers.Count == 0)
{
throw new Exception("Unable to delete a record witout unique id");
}
string PrimaryKeyName = entity.ElementType.KeyMembers[0].Name;
itemType.GetProperty(PrimaryKeyName).SetValue(item, Id, null);
}
catch (Exception ex)
{
Close(Db);
throw(ex);
}
this.Delete<T>(item, Db);
Close(Db);
#region PerformaneMonitor
}
so I am trying to convert it to Delete(object EntityType,long Id ) but no luck.
Here what it looks like :
public void Delete(object target,long Id)
{
#region PerformaneMonitor
IDbEntities Db = null;
try
{
Db = this.GetDatabase();
Type itemType = (Type)target;
EntityContainer entityContainer = Db.MetadataWorkspace.GetEntityContainer(Db.DefaultContainerName, DataSpace.CSpace);
var entity= entityContainer.BaseEntitySets.First(b => b.ElementType.Name == itemType.Name);
if (entity.ElementType.KeyMembers.Count == 0)
{
throw new Exception("Unable to delete a record witout unique id");
}
string PrimaryKeyName = entity.ElementType.KeyMembers[0].Name;
itemType.GetProperty(PrimaryKeyName).SetValue(target, Id, null);
}
catch (Exception ex)
{
Close(Db);
throw (ex);
}
this.Delete(target, Db);
Close(Db);
//_method_tag_end_
#region PerformaneMonitor
}
I am getting 'Object does not match target type' on
this line:
itemType.GetProperty(PrimaryKeyName).SetValue(target, pkey, null);
the object target is actaul instance of specific type which I do in the calling method from Type of object and using reflection and pass to this function but still I have no idea what type it is at run time.
If someone can help it will be greatly appreciated.
It sounds like you should do something along these lines: (Sorry, can't test to make sure it works as written.)
object o = itemType.GetProperty(PrimaryKeyName);
MethodInfo mi = o.GetType().GetMethod("SetValue");
mi.Invoke(o, new object [] { Id, null });