In my program I am reading in and parsing a file for resources.
I extract a string which represents the resource type, do a simple if then else statement to check if it matches any known types and throw an error if it doesn't:
if(type.toLowerCase() == "spritesheet") {
_type = ResourceType.Spritesheet;
} else if(type.toLowerCase() == "string") {
_type = ResourceType.String;
} else if(type.toLowerCase() == "texture") {
_type = ResourceType.Texture;
} else if(type.toLowerCase() == "num") {
_type = ResourceType.Number;
} else {
throw new Exception("Invalid Resource File - Invalid type: |" + type.toLowerCase() + "|");
}
Ignoring my bad naming and non descript exception, this statement is always going to the final else, even if type IS "spritesheet" as read in from the file, etc.
java.lang.Exception: Invalid Resource File - Invalid type: |spritesheet|
at Resource.Load(Resource.java:55) //Final else.
If I set type to "spritesheet" before this call, it works, so I'm wondering if it's some kind of encoding error or something?
I haven't done much work in java so I might be missing something simple :)
Assuming type is a String, you want to use String.equals() to test for equality. Using the == operator tests to see if the variables are references to the same object.
Also, to make your life easier, I would suggest using String.equalsIgnoreCase() as this will save you from calling toLowerCase().
Starting from Java 7 you can use Strings in switch statements! :)
The following should work:
switch (type.toLowerCase()) {
case "spritesheet": _type = ResourceType.Spritesheet; break;
case "string": _type = ResourceType.String; break;
case "texture": _type = ResourceType.Texture; break;
case "num": _type = ResourceType.Number; break;
default: throw new Exception("Invalid Resource File " +
"- Invalid type: |" + type.toLowerCase() + "|");
}
I haven't tried it yet, let me know how it goes!
Related
I trying to reade an Excel file with java poi. I iterate through the rows and then through the cells. To reade the cell i use this method:
private String readCell(Cell cell) {
try {
switch (cell.getCellType()) {
case NUMERIC:
if (format.isParseNumbersToInt()) {
return ((int) cell.getNumericCellValue()) + "";
} else {
return cell.getNumericCellValue() + "";
}
case STRING:
case _NONE:
return cell.getStringCellValue();
case FORMULA:
if (format.isUseCashedFormulaValue()) {
cell.removeFormula();
return readCell(cell);
} else {
return cell.getCellFormula() + "";
}
case BLANK:
return format.getBlankValue();
case BOOLEAN:
return cell.getBooleanCellValue() + "";
case ERROR:
if (format.isReadErrorCells()) {
return "ERROR_" + cell.getErrorCellValue();
} else {
return format.getErrorCellValue();
}
}
} catch (Exception e) {
throw new IllegalArgumentException("Failed to read cell: " + cell.getAddress(), e);
}
throw new IllegalStateException("Unknown CellType: " + cell.getCellType().name());
}
At one point the XmlValueDisconnectedException throws:
Caused by: org.apache.xmlbeans.impl.values.XmlValueDisconnectedException
at org.apache.xmlbeans.impl.values.XmlObjectBase.check_dated(XmlObjectBase.java:1274)
at org.apache.xmlbeans.impl.values.XmlObjectBase.getStringValue(XmlObjectBase.java:1529)
at org.apache.poi.xssf.usermodel.XSSFCell.convertSharedFormula(XSSFCell.java:491)
at org.apache.poi.xssf.usermodel.XSSFCell.getCellFormula(XSSFCell.java:469)
at org.apache.poi.xssf.usermodel.XSSFSheet.onDeleteFormula(XSSFSheet.java:4654)
at org.apache.poi.xssf.usermodel.XSSFCell.removeFormulaImpl(XSSFCell.java:571)
at org.apache.poi.ss.usermodel.CellBase.removeFormula(CellBase.java:182)
at de.heuboe.base.excel.controller.reader.ExcelReader.readCell(ExcelReader.java:356)
... 89 more
This Point looks the same as all others. The Point of the file:
enter image description here
in D219 is the string in the following cells is a referenze to the cell one row over, e.g. D220: "=D219" and D221: "=D220". The same for the columns E, F and G.
The hole file looks like this and works but at this point the programm crashes. And i don't know why.
According the StackTrace, there is a problem with a shared formula.
If you have formulas =D6, =D7, =D8, ... =D219, =D220, ... and so on in column D, then not for all cells the complete formula is stored. Instead only one cell stores the complete formula and following cells only store shared reference to the formula.
In OOXML this looks like so :
In XML of cell D8: <f ref="D8:D300" t="shared" si="1">D7</f>
In XML of cell D9:D300: <f t="shared" si="1"/>
This Excel behavior tends to be fragile if somewhat else than Excel manipulates rows containing such shared formulas.
Cell.removeFormula is a pretty new feature in apache poi. It might be buggy. But as it is designed it should know about such shared formulas and respect those. So to get what really leads to that XmlValueDisconnectedException one would need the Excel file. There one could have a look into the sheet's XML and check whether someting in the shared formula's XML is different from the default which is expected by XSSFCell.convertSharedFormula.
But do you really need Cell.removeFormula? Because if the goal is simply to get the cashed formula value instead of the formula string itself but to avoid evaluating, then one could get that cashed formula value the same way as the other cell values but dependent on the cached formula result type.
Example:
...
case FORMULA:
if (isUseCashedFormulaValue) {
//cell.removeFormula();
//return readCell(cell);
switch (cell.getCachedFormulaResultType()) {
case NUMERIC:
return String.valueOf(cell.getNumericCellValue());
case STRING:
return cell.getStringCellValue();
case BOOLEAN:
return String.valueOf(cell.getBooleanCellValue());
case ERROR:
return "ERROR_" + cell.getErrorCellValue();
}
} else {
return cell.getCellFormula();
}
...
There are a lot of if-else statements in my code what is the best way that I can avoid so many if-else statements. Below is the code snippet. Now again I need to check if WWW-Authenticate header returns value
signature_invalid
then I need to log and return a different error message and if WWW-Authenticate header returns value
token_exppured
then I need to log a different error message which will again add 2 more ifs. Can anyone Help me how can I avoid this??
if (e.getRawStatusCode() == NOT_FOUND) {
logger.log(
log,
LogLevel.ERROR,
MISSING_VALID_ID_ERROR_MSG + " : " + e.toString(),
viewRequest);
String errorDetails = createNotFoundDetails(appl, transactionId);
updateIdentifier(rcvLog, true, request, identifier);
return createErrorViewResponseReply(MISSING_VALID_ID_ERROR_MSG, errorDetails);
} else if (e.getRawStatusCode() == UNAUTHORIZED) {
logger.log(
log,
LogLevel.ERROR,
UNABLE_TO_REACH_ERROR_MSG + " : " + e.toString(),
viewRequest);
if (e.getResponseHeaders() != null && e.getResponseHeaders().getFirst(HttpHeaders.WWW_AUTHENTICATE != null)) {
logger.log(
log,
LogLevel.ERROR,
INVALID_TOKEN_ERROR_MSG + " : " + e.getResponseHeaders().getFirst(HttpHeaders.WWW_AUTHENTICATE),
viewRequest);
}
updateIdentifier(rcvLog, false, request, identifier);
return createErrorViewResponseReply(
UNABLE_TO_REACH_ERROR_MSG,
INVALID_TOKEN_ERROR_DETAILS);
}
The basic approaches one can take with this is:
Create a class hierarchy with a factory to instantiate the right instance to respond to the action
Do the same but in short hand with Enums
Use a map of this::method() and call your methods that do the work for you
For your case, since you can't really control the types of code an API sends you, and a factory method may be overkill, a map approach may be best:
map.put(NOT_FOUND, this::methodA);
map.put(UNAUTHORIZED, this::methodB);
map.put(OTHER, this::methodC);
map.computeIfAbsent(
e.getRawStatusCode(),
(e, rc, req, id) -> {/** NOTHING */}
).apply(e, rcvLog, request, identifier);
computeIfAbsent() allows you to handle the unhandled case with basically a no-op.
I tried to convert my if-else statements into a switch case but I had the following problem.
Old code:
if (properties.get("database").toString().equalsIgnoreCase("SQLSERVER")) {
manager = new CManagingSQLServer();
} else if (properties.get("database").toString().equalsIgnoreCase("ORACLE")){
manager = new CManagingOracle();
} else if (properties.get("database").toString().equalsIgnoreCase("MYSQL")){
manager = new CManagingMySQL();
} else {
System.out.println("Not supported DB: " + properties.get("database").toString() + "\n");
System.out.println("Supported DB:");
System.out.println("- ORACLE");
System.out.println("- SQLSERVER");
System.out.println("- MYSQL");
System.exit(0);
}
New code:
String database = properties.get("database").toString();
switch (database) {
case database.equalsIgnoreCase("SQLSERVER"):
manager = new CManagingSQLServer();
break;
case database.equalsIgnoreCase("ORACLE"):
manager = new CManagingOracle();
break;
case database.equalsIgnoreCase("MYSQL"):
manager = new CManagingMySQL();
break;
default:
System.out.println(database + "is not a supported database.");
System.exit(0);
break;
}
First, the String database threw an error that I have to change setting/property (actually don't know) into version 1.7?! After doing so, my cases are throwing now errors. They say: Type mismatch cannot convert from boolean to String.
I read other SO-thread and they said I have to try (String)something or something.ToString(). But both cases didn't work and I don't understand what changed with the above mentioned change to version 1.7.
And how can I make my cases work again?
Change database variable to
String database = properties.get("database").toString().toUpperCase();
And switch case to
case "SQLSERVER":
Currently, you are getting error because database.equalsIgnoreCase("SQLSERVER") returns boolean but you are switching on database which is a String.
Also, you need to use minimum of Java 7 because Java versions before that don't support switch case on String.
The problem you are facing is that in switch you pass a String typed database.
In case of section you want to work with boolean expression database.equalsIgnoreCase(...).
The easiest way to deal with that is to change the line:
String database = properties.get("database").toString();
to:
String database = properties.get("database").toString().toUpperCase();
and in case section use simple approach (as you have already upper cased database variable):
case "SQLSERVER"
instead of
case database.equalsIgnoreCase("SQLSERVER")
INFORMATION:
Switch expressions that work with strings are available from JDK 7.
you are missing the whole concept of switch case , you don't have to put equal condtion in your switch case.
just put like this it will work fine
String database = properties.get("database").toString().toUpperCase();
switch (database) {
case "SQLSERVER":
manager = new CManagingSQLServer();
break;
case "ORACLE":
manager = new CManagingOracle();
break;
case "MYSQL":
manager = new CManagingMySQL();
break;
default:
System.out.println(database + "is not a supported database.");
System.exit(0);
break;
}
Use the string value in case statements.
Case "SQLSERVER":
So I'm making a simple code redemption plugin for a Minecraft server. What's weird is when I type /redeem (the valid code), nothing happens, although it's supposed to... The valid code is the a code entered into the plugins configuration by the user.
Here's my code...
public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args)
{
//Assigns the commands chosen in config to strings
String commandChosen1 = this.getConfig().getString("Command for code 1");
String commandChosen2 = this.getConfig().getString("Command for code 2");
String commandChosen3 = this.getConfig().getString("Command for code 3");
//Assigns the codes to strings
String validCode1 = this.getConfig().getString("Valid Code 1");
String validCode2 = this.getConfig().getString("Valid Code 2");
String validCode3 = this.getConfig().getString("Valid Code 3");
//If the redeem command is sent from a player
if(cmd.getName().equalsIgnoreCase("redeem") && sender instanceof Player)
{
//Casts the sender to a new player.
Player player = (Player) sender;
//Creates object hasUSed to store whether or not the player has already redeemed a code
Object hasUsed = this.getConfig().get(player.getName());
//Gives an error message of the arguments don't equal 1.
if(args.length != 1)
{
player.sendMessage(ChatColor.DARK_RED + "Please enter a valid promo code. Find them on our twitter!");
}
if(args.length == 1)
{
//If the player hasn't used the code yet and the arguments given are equal to a code then give them the reward...
if(args[0] == validCode1 && hasUsed == null)
{
this.getConfig().set(player.getName(), 1);
player.sendMessage(ChatColor.GREEN + "Promo code successfully entered!");
if(commandChosen1 == "xp")
{
Bukkit.dispatchCommand(player, commandChosen1 + getConfig().getString("XP Given") + "L" + " " + player.getName());
}
}
}
return true;
}
return false;
}
The problem occurs on "if (args[0] == validCode1 && hasUsed == null)". The code that's supposed to happen if both those things check out, doesn't happen and I have no clue why.
Make sure to use equals() when comparing Strings. Using commandChosen1 == "xp" compares string references not values; use commandChosen1.equals("xp") or if you prefer "xp".equals(commandChosen1).
Also,
While it is possible to use a this.getConfig().getString()with a key value that contains spaces, it can make configuration files hard to read and cluttered. Whenever I design plugins I'll design my config.yml as such
VoteGUI:
message: 'hello'
and then run a this.getConfig().getString("VoteGUI.message");
For yours I'd suggest something like this
Promo-Codes:
validCode1: 'insert code here'
validCode2: 'insert code here'
validCode3: 'insert code here'
and then put this in your onCommand method:
String validCode1 = this.getConfig().getString("Promo-Codes.validCode1");
String validCode2 = this.getConfig().getString("Promo-Codes.validCode2");
String validCode3 = this.getConfig().getString("Promo-Codes.validCode3");
If this does not resolve the issue, copy and paste the exception being thrown from the console and I may be of further assistance
When using a directory-expression for an <int-file:outbound-gateway> endpoint, the method below is called on org.springframework.integration.file.FileWritingMessageHandler:
private File evaluateDestinationDirectoryExpression(Message<?> message) {
final File destinationDirectory;
final Object destinationDirectoryToUse = this.destinationDirectoryExpression.getValue(
this.evaluationContext, message);
if (destinationDirectoryToUse == null) {
throw new IllegalStateException(String.format("The provided " +
"destinationDirectoryExpression (%s) must not resolve to null.",
this.destinationDirectoryExpression.getExpressionString()));
}
else if (destinationDirectoryToUse instanceof String) {
final String destinationDirectoryPath = (String) destinationDirectoryToUse;
Assert.hasText(destinationDirectoryPath, String.format(
"Unable to resolve destination directory name for the provided Expression '%s'.",
this.destinationDirectoryExpression.getExpressionString()));
destinationDirectory = new File(destinationDirectoryPath);
}
else if (destinationDirectoryToUse instanceof File) {
destinationDirectory = (File) destinationDirectoryToUse;
} else {
throw new IllegalStateException(String.format("The provided " +
"destinationDirectoryExpression (%s) must be of type " +
"java.io.File or be a String.", this.destinationDirectoryExpression.getExpressionString()));
}
validateDestinationDirectory(destinationDirectory, this.autoCreateDirectory);
return destinationDirectory;
}
Based on this code I see that if the directory to use evaluates to a String, it uses that String to create a new java.io.File object.
Is there a reason that a ResourceLoader couldn't/shouldn't be used instead of directly creating a new file?
I ask because my expression was evaluating to a String of the form 'file://path/to/file/' which of course is an invalid path for the java.io.File(String) constructor. I had assumed that Spring would treat the String the same way as it treats the directory attribute on <int-file:outbound-gateway> and pass it through a ResourceLoader.
Excerpt from my configuration file:
<int-file:outbound-gateway
request-channel="inputChannel"
reply-channel="updateTable"
directory-expression="
'${baseDirectory}'
+
T(java.text.MessageFormat).format('${dynamicPathPattern}', headers['Id'])
"
filename-generator-expression="headers.filename"
delete-source-files="true"/>
Where baseDirectory is a property that changes per-environment of the form 'file://hostname/some/path/'
There's no particular reason that this is the case, it probably just wasn't considered at the time of implementation.
The request sounds reasonable to me and will benefit others (even though you have found a work-around), by providing simpler syntax. Please open an 'Improvement' JIRA issue; thanks.
While not directly answering the question, I wanted to post the workaround that I used.
In my XML configuration, I changed the directory-expression to evaluate to a file through the DefaultResourceLoader instead of a String.
So this is what my new configuration looked like:
<int-file:outbound-gateway
request-channel="inputChannel"
reply-channel="updateTable"
directory-expression=" new org.springframework.core.io.DefaultResourceLoader().getResource(
'${baseDirectory}'
+
T(java.text.MessageFormat).format('${dynamicPathPattern}', headers['Id'])).getFile()
"
filename-generator-expression="headers.filename"
delete-source-files="true"/>