How to retrieve error message in StringTemplate? - java

How can I retrieve a compile time error message from StringTemplate as a String?
This code for instance:
STGroup stg = new STGroup('<', '>');
CompiledST compiledTemplate = stg.defineTemplate("receipt", "<an invalid template<>");
if (compiledTemplate == null)
System.out.println("Template is invalid");
Will simply log something like "invalid came as a complete surprise to me", but I want to display this error message in my UI.
I can access the ErrorManager with stg.errMgr. I expected a method like getErrors() here, but there isn't...

You could set an error listener for the group, which would allow you to catch the error, and then pass it to the UI from there.
This answer tells you more about implementing an STErrorListener. The example they give doesn't compile since they're throwing checked exceptions from within the ErrorListener. Perhaps a better approach would be to handle the errors directly inside the listener, or you could just throw a RuntimeException so you could catch the errors when you call stg.defineTemplate(...).
public class MySTErrorListener implements STErrorListener {
...
#Override
public void compileTimeError(STMessage msg) {
// do something useful here, or throw new RuntimeException(msg.toString())
}
...
}
If you were to throw the RuntimeException you could then catch it when you define the ST:
stg.setListener(new MySTErrorListener());
try{
CompiledST compiledTemplate = stg.defineTemplate("receipt", "<an invalid template<>");
} catch (Exception e)
{
// tell the UI about the error
}

Related

how to try...catch a feign exception and return only the status code and the erro message

I'm working on a SpringBootApplication. In this app I have 4 micro-services using Feign to communicate between eachothers. In a Controller I have a piece of code like this below, to catch exceptions and return it to the view, in case something is wrong.
try {
patientDTO = patientProxyFeign.getPatientById(id);
noteDTOList = historyProxyFeign.getAll(id);
assessmentDTO = assessmentProxyFeign.getPatientAssessment(id);
} catch (Exception e) {
log.error("" + e.getMessage());
model.addAttribute("errorMsg", e.toString());
return "error/error";
}
If there is an exception I got a message like this to the view :
feign.FeignException$NotFound: [404] during [GET] to [http://localhost:8081/patient/12000] [PatientProxyFeign#getPatientById(Integer)]: [{"timestamp":"2021-12-16T16:21:27.790+00:00","status":404,"error":"Not Found","path":"/patient/12000"}]
What I want to do, is to get only the status code and the message "not found".
Is someone got an idea how to do it ? (Search on google, but seems to be too specific. I probably don't use the right keywords.)
You can get the status by calling e.status() and then you can switch-case the status and get a message based on that. You could also build a Map of <Integer, String> and get the message by status. To read about FeignException more kindly visit https://github.com/OpenFeign/feign/blob/master/core/src/main/java/feign/FeignException.java
And it is strongly advisable to be specific about what you catch:
} catch (FeignException e) {

What happens if one filter throws Exceptions in servlet?

I want to add a filter to an existing project, and don't expect my filter to affect the original process in abnormal case. In any cases, the original filter should be executed.
So, I want to know, how should I process when I catch an Exception:
throw the Exception
catch the Exception and call chain.doFilter();
do nothing, like the following code:
if (filter != null) {
filter.doFilter(req,resp,chain);
// should I catch the exception here?
} else {
chain.doFilter(req,resp);
}
Thanks all.
nest your try-catch block inside if(filter!=null)
For instance:
if(filter != null){
try{} catch (Exception e){
//do something
}
}
Also you can use finally after catch for any clean up or code you want to run no whether an exception is caught or not.

ClassCastException in spring

I am trying to catch an exception and return a value to my client page, but I get ClassCastException and it is not returning any value.
My code snippet-
#RequestMapping(value = "/config/MyFile/data", method = RequestMethod.GET)
#ResponseBody
public List<Myfile> getAllFlatFileTrafficCops()
{
try
{
return MyFileServices.getAlldata();
}
catch (final ResourceAccessException r)
{
final Throwable flatfileTrafficCopStatus;
flatfileTrafficCopStatus = r.getCause();
return (List<FlatFileTrafficCop>) flatfileTrafficCopStatus;
}
}
All you can do in this case in Exception situation catch the exception and encapsulate it in your meaningful custom exception and propagate it back to caller function and for web display meaningful error text.
Always propagate exceptions back to caller. For debug you might want to add a log statement over there.
catch (final ResourceAccessException r)
{
CustomException cException = new CustomException(r);
throw cException;
//OR
FlatFileTrafficCop emptyObj= new FlatFileTrafficCop(Witherr);
//add that in a list and return
}
first is ClassCastException child of ResourceAccessException? No, so your catch will not work, if you want to catch ClassCastException you have to make 2nd catch for it
catch (final ClassCastException e){}
but while you are using spring no need to catch it like this you can use #ExceptionHandler instead

How to write to log file when test fail, with Log4j

I want to achieve writing to log file with Log4j.
I have found one easy solution - surround test body with try - catch:
#Test(groups = "GMAIL_PAGE")
public void testAllMailLink() {
try {
List<WebElement> allMessages = page.takeAllMessage();
page.clickInboxLink();
List<WebElement> inboxMessages = page.takeInboxMessage();
page.clickDraftLink();
List<WebElement> draftMessages = page.takeDraftMessage();
Assert.assertTrue(allMessages.containsAll(inboxMessages),
"All messages doesn't contains all inbox messages");
Assert.assertTrue(allMessages.containsAll(draftMessages),
"All messages doesn't contains all draft messages");
log.info("test is passed");
} catch (Exception e) {
log.error(e);
}
}
But it has some drawbacks - this test is always passed, even if it fails.
It is ok if I work on my machine and able to see console. But what to do when this test is pushed to Continuous Integration server?
Does exist any other way to write info into log file, when test fail?
Add Assert.fail() below your log.error(e):
catch (Exception e) {
log.error(e);
Assert.fail();
}
By the way, you're calling Logger#error(Object), which uses e.toString(). In this case, it is better to use a descriptive message and then pass the exception to get the respective stacktrace:
catch (Exception e) {
log.error("Some descriptive message should go here.", e);
Assert.fail("Some descriptive message should go here as well.");
}

How is this execution flow possible?

I've got a pretty straightforward Java webapp that has been showing some very strange behavior on development systems. The problem starts with the registration handler, which is implented as follows:
//XXX: this shouldn't really be 'synchronized', but I've declared it as such
// for the sake of debugging this issue
public synchronized ModelAndView submitRegister(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String email = request.getParameter("email");
String pass = request.getParameter("pass");
String conf = request.getParameter("conf");
String name = request.getParameter("name");
EntityManager em = DatabaseUtil.getEntityManager(request);
//[make sure required fields are present and valid, etc.]
User user = getUserForEmail(email, em);
if (user != null) {
//[user already exists, go to error page]
}
//create the new user
em.getTransaction().begin();
try {
user = new User();
//[set fields, etc.]
em.persist(user);
//[generate e-mail message contents]
boolean validEmail = EmailUtility.sendEmail(admin, recip, subject, message, null, recip);
if (validEmail) {
em.getTransaction().commit();
//[go to 'registration successful' page]
}
em.getTransaction().rollback();
//[go to error page]
}
catch (Exception e) {
em.getTransaction().rollback();
//[go to error page]
}
}
The problem occurs on the EmailUtility.sendEmail() call. The code for this method is pretty straightforward:
public static boolean sendEmail(String fromAddress, String to, String subject, String message, String fromHeaderValue, String toHeaderValue) {
try {
Session session = getMailSession(to);
Message mailMessage = new MimeMessage(session);
mailMessage.setFrom(new InternetAddress(fromAddress));
if (fromHeaderValue != null) {
mailMessage.setHeader("From", fromHeaderValue);
}
if (toHeaderValue != null) {
mailMessage.setHeader("To", toHeaderValue);
}
mailMessage.setHeader("Date", new Date().toString());
mailMessage.setRecipients(RecipientType.TO, InternetAddress.parse(to, false));
mailMessage.setSubject(subject);
mailMessage.setContent(message, "text/html;charset=UTF-8");
Transport.send(mailMessage);
return true;
} catch (Throwable e) {
LOG.error("Failed to send e-mail!", e);
return false;
}
}
What happens is that when the code reaches the call for EmailUtility.sendEmail(), instead of calling that method execution recurses through submitRegister(). That's easily one of the most bizarre things I've ever seen.
For awhile I didn't even believe that was what's actually happening; but at this point I've confirmed it by synchronizing the method involved and adding print statements on every line of both methods. submitRegister() recurses, and sendEmail() is never called. I've got no idea how this is even possible.
Frustratingly, the exact same code runs just as it should on the production server. It's only on development systems that this problem appears.
Any suggestions regarding what might be causing this problem and what I can do to fix it are welcome.
You are right, This is not possible :)
I would suggest you strip away all other code, put in a lot of logging, if you don't like debugging and see what happens. Start with something like:
public synchronized ModelAndView submitRegister(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
LOG.debug("submitRegister: " + this.toString);
EmailUtility.sendEmail("a#x.y", "b#x.y", "subject", "message", "from", "to");
}
public static boolean sendEmail(String fromAddress, String to, String subject, String message, String fromHeaderValue, String toHeaderValue) {
LOG.debug("sendEmail: " + this.toString());
}
The toString will show you what classes are involved.
My guess would be that:
your first call fails, so sendEmail will never be invoked
submitRegister is triggered more than once by someone else, not by the EmailUtility.sendEmail statement.
If you get the stripped version to work, start putting back your code, one peace at a time to see where it all goes bad :)
Okay, I tracked this down to a few different issues working together:
On development systems, the classpath was missing javax.mail.Address. This caused the EmailUtility class to fail to initialize, and would throw a NoClassDefFoundError on the sendEmail() call, before any code from that method could execute.
The code in submitRegister() had a catch Exception block, but NoClassDefFoundError extends Error, not Exception. So it bypassed the catch Exception block entirely.
The Spring controller where the Error was actually caught had some of the most questionable "error-handling" code I've ever come across:
try {
Method serviceMethod = this.getControllerClass().getMethod(method, HttpServletRequest.class, HttpServletResponse.class);
if (this.doesMethodHaveAnnotation(serviceMethod, SynchronizedPerAccount.class)) {
synchronized(this.getAccountLock(request)) {
super.doService(request, response);
}
}
else {
//don't need to execute synchronously
super.doService(request, response);
}
}
catch (Throwable ignored) {
super.doService(request, response);
}
So the NoClassDefFoundError was propagating back up to the Spring controller, which was catching it and attempting to re-invoke the doService() method, which caused submitRegister() to be invoked again. It wasn't recursion (though there was no way to tell that by just looking at the debug output), it was the Spring controller calling it twice for the same request. It never got called more than twice for a given request, because there's no try/catch around the second doService() call.
Long story short, I patched up these issues and problem solved.

Categories