addition to Managed Bean Best Practice - java

This is an extension to ( Managed-Bean best practice ). I have written a class AppProperties that defines the various items in the Class:
public class AppProperties implements Serializable {
private static final long serialVersionUID = 1L;
//contents of AppProperties Object
private String appRepID;
private String helpRepID;
private String ruleRepID;
private String filePath;
private Vector formNames;
//end content
private Session s;
private String serverName;
public String getAppRepID() {
return appRepID;
}
public void setAppRepID(String appRepID) {
this.appRepID = appRepID;
}
//rest if getters and setters
}
In my bean I have the following:
import ca.wfsystems.core.AppProperties;
private final Map<String, AppProperties> internalMap = new HashMap<String, AppProperties>();
public ApplicationMap() {
this.buildMap(internalMap);
}
private void buildMap(Map<String, AppProperties> theMap) {
try{
AppProperties ap = null;
Session s = ExtLibUtil.getCurrentSession();
vwApps = s.getCurrentDatabase().getView("vwWFSApplications");
veCol = vwApps.getAllEntries();
ve = veCol.getFirstEntry();
tVE = null;
while (ve != null){
Vector colVal = ve.getColumnValues();
String tAppRepID = colVal.get(2).toString();
ap.setAppRepID(colVal.get(2).toString());
ap.setHelpRepID(colVal.get(3).toString());
ap.setRuleRepID(colVal.get(4).toString());
theMap.put(colVal.get(0).toString(), ap);
}
}catch(Exception e){
System.out.println(e.toString());
}finally{
Utils.recycleObjects(s,vwApps);
}
}
everything seems to be ok except at ap.setAppRepID(colVal(2).toString()) there is a compiler error that "Null pointer access The variable ap can only be null at this point" the code for the setAppRepID and setHelpRepID are identical and there is no compiler error of either setHelpRepID or setRuleRepID. I'm not sure if the problem is in the setting AppProperties ap = null tried to create AppProperties ap = new AppProperties but it doesn't like that. I think I'm really close to making this work but ....
Thanks to all who have been very patient with me as I climb up the JAVA slope.

the compiler error is correct, your variable ap can only be null at that point.
Follow each statement from
AppProperties ap = null;
to
ap.setAppRepID(colVal.get(2).toString());
and at no point is ap initialised to an object, it will still be null.
You would also see the compiler error on setHelpRepID or setRuleRepID as well but it doesn't bother showing you because it is already a problem with the first statement. You can try this by commenting out the setAppRepID line and you should see the same error on the next line.
make a public constructor in your AppProperties class
public AppProperties() {};
and then try to change
AppProperties ap = null;
to
AppProperties ap = new AppProperties();

It's definitely the "AppProperties ap = null" line. When you say that you tried "AppProperties ap = new AppProprties", did you include "()" at the end (i.e. "AppProperties ap = new AppProperties()")? It looks like your AppProperties bean has the default argumentless constructor, so that should work. Specifically, guessing from your code, I expect you'll want to move that line to just after the opening of the while loop.
You also have an infinite loop lying in wait: you never set the entry to the next one in the while loop. If you're not using the OpenNTF Domino API, I suggest an idiom like this:
ViewEntry entry = veCol.getFirstEntry();
while(entry != null) {
Vector<?> colVal = ve.getColumnValues();
...
entry.recycle(colVal);
ViewEntry tempEntry = entry;
entry = veCol.getNextEntry();
tempEntry.recycle();
}

Related

How to test function which calls another void function from it with static value as argument using mockito

I have a class A as
Class A{
private static final String ANON_DIR = "/webapps/worldlingo/data/anonymizer/";
private static final String NO_ANON = "noanonymize";
public String first(String text, String srclang, Map dictTokens) {
Set<String> noAnonymize = new HashSet<String>();
second(noAnonymize,ANON_DIR + NO_ANON, "tmpLang","name");
String value;
if(noAnonymize.contains("test")){
value = word;
}
else {
value = "test";
}
return value;
}
where ANON_DIR and NO_ANON is static final value. This class has function first and function second .The first function has a calling method in it which calls second function. The second function is void function which takes static fields as parameter.
Second function is just the file read function with the path provided as
private void second (Set<String> hashSet, String path, String lang , String type) {
FileReader fr = null;
BufferedReader br = null;
try {
fr = new FileReader(path);
br = new BufferedReader(fr);
String Line;
while ((Line = br.readLine()) != null) {
hashSet.add(Line);
}
} catch (IOException e) {
log.error("Anonymizer: Unable to load file.", e);
} finally {
try {
if (fr != null) {
fr.close();
}
if (br != null) {
br.close();
}
} catch (IOException e) {
log.error("Anonymizer : An error occured while closing a resource.", e);
}
}
}
}
Now I am trying to test the function first using mockito. I am trying to change the static parameter and send those changed static parameter as
public void testfirst() throws Exception {
A anon = new A();
Field ANON_DIR = A.class.getDeclaredField("ANON_DIR");
ANON_DIR.setAccessible(true);
//java relection to change private static final field
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(ANON_DIR, ANON_DIR.getModifiers() & ~Modifier.FINAL);
ANON_DIR.set(null,"test");
Field NO_ANON = A.class.getDeclaredField("NO_ANON");
NO_ANON.setAccessible(true);
Field modifiersField1 = Field.class.getDeclaredField("modifiers");
modifiersField1.setAccessible(true);
modifiersField1.setInt(NO_ANON, NO_ANON.getModifiers() & ~Modifier.FINAL);
NO_ANON.set(null,"/noanonymize");
Method anonymizeNames = anon.getClass().getDeclaredMethod("first", String.class, String.class , Map.class);
String srcLang = "MSFT_EN";
Map mapTokens = new HashMap();
String result = (String) anonymizeNames.invoke(anon,"I am David",srcLang,mapTokens);
}
PROBLEM:
Here I could change the private final static field ANON_DIR and NO_ANON using java reflection but the changed field are not send to the second function. The second function called from first function takes the original value instead of changed value. i.e when the second is called ANON_DIR has
"/webapps/worldlingo/data/anonymizer/" value instead of "test".
Since I changed the value of ANON_DIR to "test" I want the same "test" value to be passed to the second function. How can I acheive this for testing for void second method.
The problem here is the violation of the Separation of concerns principle.
Your code under test (cut) does too much and thus you have a hard time to find seams to replace dependencies.
Also there is a misunderstanding of the aim of unittests. You don't test code, you test public observable behavior which is any return value and communication with dependencies (but not necessarily public methods).
So my suggestion is to move method second() to a new class of its own. The cut gets an instance of this new class passed in as constructor parameter.
Then it is easy to replace the real dependency with a mock of that new class in your test.
On the other hand you could simple surrender to your bad design by using PowerMock...

How to clone old builder to make a new builder object?

I have a builder class which I am using in one of my project.
Let's say I have metricA as builder based on below class.
I need to make a new builder metricB based on metricA by cloning metricA so that metricB contains all the values which were already there in metricA.
In the constructor of MetricHolder I am initializing some fields (which are not set directly) basis on fields that have been set already.
clientTypeOrPayId - I am initializing this field. If payId is present, then I will set this value or I will set clientType.
clientKey - I am initializing this field as well in the same constructor.
And most importantly, I am putting few mandatory fields in the clientPayload map. I am not sure what is the right way to do that. But I need to add is_clientid and is_deviceid into the map. (In general I am adding few more fields).
And then in the last of the constructor, I am calculating latency difference and sending it to some other system.
Below is my class:
public final class MetricHolder {
private final String clientId;
private final String deviceId;
private final String payId;
private final String clientType;
private final String clientTypeOrPayId;
private final Schema schema;
private final String schemaId;
private final String clientKey;
private final Map<String, String> clientPayload;
private final Record record;
private final long clientCreateTimestamp;
private final long clientSentTimestamp;
private MetricHolder(Builder builder) {
this.payId = builder.payId;
this.siteId = builder.siteId;
this.clientType = builder.clientType;
this.clientId = builder.clientId;
this.deviceId = builder.deviceId;
this.schema = builder.schema;
this.schemaId = builder.schemaId;
// populating all the required fields in the map and make it immutable
// not sure whether this is right?
builder.clientPayload.put("is_clientid", (clientId == null) ? "false" : "true");
builder.clientPayload.put("is_deviceid", (clientId == null) ? "true" : "false");
this.clientPayload = Collections.unmodifiableMap(builder.clientPayload);
this.clientTypeOrPayId = Strings.isNullOrEmpty(payId) ? clientType : payId;
this.record = builder.record;
this.clientKey = "process:" + System.currentTimeMillis() + ":"
+ ((clientId == null) ? deviceId : clientId);
this.clientCreateTimestamp = builder.clientCreateTimestamp;
this.clientSentTimestamp = builder.clientSentTimestamp;
// this will be called twice while cloning
// what is the right way to do this then?
SendData.getInstance().insert(clientTypeOrPayId,
System.currentTimeMillis() - clientCreateTimestamp);
SendData.getInstance().insert(clientTypeOrPayId,
System.currentTimeMillis() - clientSentTimestamp);
}
public static class Builder {
private final Record record;
private Schema schema;
private String schemaId;
private String clientId;
private String deviceId;
private String payId;
private String clientType;
private Map<String, String> clientPayload;
private long clientCreateTimestamp;
private long clientSentTimestamp;
// this is for cloning
public Builder(MetricHolder packet) {
this.record = packet.record;
this.schema = packet.schema;
this.schemaId = packet.schemaId;
this.clientId = packet.clientId;
this.deviceId = packet.deviceId;
this.payId = packet.payId;
this.clientType = packet.clientType;
// make a new map and check whether mandatory fields are present already or not
// and if they are present don't add it again.
this.clientPayload = new HashMap<>();
for (Map.Entry<String, String> entry : packet.clientPayload.entrySet()) {
if (!("is_clientid".equals(entry.getKey()) || "is_deviceid".equals(entry.getKey())) {
this.clientPayload.put(entry.getKey(), entry.getValue());
}
}
this.clientCreateTimestamp = packet.clientCreateTimestamp;
this.clientSentTimestamp = packet.clientSentTimestamp;
}
public Builder(Record record) {
this.record = record;
}
public Builder setSchema(Schema schema) {
this.schema = schema;
return this;
}
public Builder setSchemaId(String schemaId) {
this.schemaId = schemaId;
return this;
}
public Builder setClientId(String clientId) {
this.clientId = clientId;
return this;
}
public Builder setDeviceId(String deviceId) {
this.deviceId = deviceId;
return this;
}
public Builder setPayId(String payId) {
this.payId = payId;
return this;
}
public Builder setClientType(String clientType) {
this.clientType = clientType;
return this;
}
public Builder setClientPayload(Map<String, String> payload) {
this.clientPayload = payload;
return this;
}
public Builder setClientCreateTimestamp(long clientCreateTimestamp) {
this.clientCreateTimestamp = clientCreateTimestamp;
return this;
}
public Builder setClientSentTimestamp(long clientSentTimestamp) {
this.clientSentTimestamp = clientSentTimestamp;
return this;
}
public MetricHolder build() {
return new MetricHolder(this);
}
}
// getters
}
Question:-
Below is how I make metricA builder object:
MetricHolder metricA = new MetricHolder.Builder(record).setClientId("123456").setDeviceId("abcdefhg")
. setPayId("98765").setClientPayload(payloadMapHolder).setClientCreateTimestamp(createTimestamp)
.setClientSentTimestamp(sentTimestamp).build();
Now this is how I clone the metricA object later on in the code when I get all other fields as shown below:
MetricHolder metricB = new MetricHolder.Builder(metricA).setSchema(schema).setSchemaId("345").build();
I see two problem now:
First of all, my SendData.getInstance() line in the MetricHolder constructor will be called twice. First is when I make metricA and second when I make metricB by cloning metricA. But I just want to call it only once when I try to create metricA builder object? How can I make this possible?
Second is, the way I am populating clientPayload map with two mandatory fields in the MetricHolder constructor doesn't look right to me. Is there any other better way to do the same thing?
I guess the whole problem is happening because the way I am cloning metricA to make a metricB builder object? What is the best way to do this? I want to achieve above two things but in a right way.
But I just want to call it only once when I try to create metricA builder object? How can I make this possible?
The most straightforward way is to have a flag in the builder indicating whether it was created by Record or by cloning:
class Builder {
final boolean cloned;
Builder(MetricHolder packet) {
this.cloned = true;
// ...
}
Builder(Record record) {
this.cloned = false;
// ...
}
}
Then, in the constructor of MetricHolder:
if (!builder.cloned) {
SendData.getInstance().whatever();
}
But it's worth pointing out that making this call to SendData is an example of doing too much work in the constructor. You should think carefully about whether you really want to be making this call in the constructor, or whether you can factor that out into another method.
Second is, the way I am populating clientPayload map with two mandatory fields in the MetricHolder constructor doesn't look right to me. Is there any other better way to do the same thing?
You've misunderstood the "unmodifiable" bit of using Collections.unmodifiableMap: it's only an unmodifiable view of the map parameter; you can still modify the underlying map.
Here's a JUnit test to demonstrate:
Map<String, String> original = new HashMap<>();
original.put("hello", "world");
// Obviously false, we just put something into it.
assertFalse(original.isEmpty());
Map<String, String> unmodifiable = Collections.unmodifiableMap(original);
// We didn't modify the original, so we don't expect this to have changed.
assertFalse(original.isEmpty());
// We expect this to be the same as for the original.
assertFalse(unmodifiable.isEmpty());
try {
unmodifiable.clear();
fail("Expected this to fail, as it's unmodifiable");
} catch (UnsupportedOperationException expected) {}
// Yep, still the same contents.
assertFalse(original.isEmpty());
assertFalse(unmodifiable.isEmpty());
// But here's where it gets sticky - no exception is thrown.
original.clear();
// Yep, we expect this...
assertTrue(original.isEmpty());
// But - uh-oh - the unmodifiable map has changed!
assertTrue(unmodifiable.isEmpty());
The thing is that the map is only unmodifiable if there is no other reference to it hanging around: if you don't have a reference to original, unmodifiable actually is unmodifiable; otherwise, you can't rely upon the map never changing.
In your particular case, you are simply wrapping the clientPayload map in your unmodifiable collection. So, you're overwrite values for previously-constructed instances.
For example:
MetricHolder.Builder builder = new MetricHolder.Builder();
MetricHolder first = builder.build();
assertEquals("false", first.clientPayload.get("is_clientid"));
assertEquals("true", first.clientPayload.get("is_deviceid"));
builder.setClientId("").build();
// Hmm, first has changed.
assertEquals("true", first.clientPayload.get("is_clientid"));
assertEquals("false", first.clientPayload.get("is_deviceid"));
The correct approach is not to wrap builder.clientPayload. Take a copy of the map, modify it, and then wrap with unmodifiableMap:
{
Map<String, String> copyOfClientPayload = new HashMap<>(builder.clientPayload);
copyOfClientPayload.put("is_clientid", (clientId == null) ? "false" : "true");
copyOfClientPayload.put("is_deviceid", (clientId == null) ? "true" : "false");
this.clientPayload = Collections.unmodifiableMap(copyOfClientPayload);
}
The surrounding {} aren't strictly necessary, but they restrict the scope of copyOfClientPayload, so you can't accidentally reuse it later in the constructor.

Passing values from database in "allowableValues"?

I am using Swagger version 2 with Java Spring. I have declared a property and it works fine and it generates a drop down list of value I assigned.
#ApiParam(value = "Pass any one Shuttle provider ID from the list", allowableValues = "1,2,3,4,10")
private Long hotelId;
Now, I need a way to populate this list which is passed in allowableValues from my database as it could be random list as well as huge data. How can I assign list of values dynamically from database in this allowableValues?
This question is bit old, I too faced the same problem so thought of adding here which may help some one.
//For ApiModelProperty
#ApiModelProperty(required = true, allowableValues = "dynamicEnum(AddressType)")
#JsonProperty("type")
private String type;
Created a component which implements ModelPropertyBuilderPlugin
#Component
#Order(SwaggerPluginSupport.SWAGGER_PLUGIN_ORDER + 1)
public class ApiModelPropertyPropertyBuilderCustom implements ModelPropertyBuilderPlugin {
private final DescriptionResolver descriptions;
#Autowired
public ApiModelPropertyPropertyBuilderCustom(DescriptionResolver descriptions) {
this.descriptions = descriptions;
}
public void apply(ModelPropertyContext context) {
try {
AllowableListValues allowableListValues = (AllowableListValues) FieldUtils.readField(context.getBuilder(),
"allowableValues", true);
if(allowableListValues!=null) {
String allowableValuesString = allowableListValues.getValues().get(0);
if (allowableValuesString.contains("dynamicEnum")) {
String yourOwnStringOrDatabaseTable = allowableValuesString.substring(allowableValuesString.indexOf("(")+1, allowableValuesString.indexOf(")"));
//Logic to Generate dynamic values and create a list out of it and then create AllowableListValues object
context.getBuilder().allowableValues(allowableValues);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
public boolean supports(DocumentationType delimiter) {
return SwaggerPluginSupport.pluginDoesApply(delimiter);
}
}
Similary for ApiParam we can create component which will implement ParameterBuilderPlugin
#Override
public void apply(ParameterContext context) {
#SuppressWarnings("Guava") final Optional<ApiParam> apiParam =
context.resolvedMethodParameter().findAnnotation(ApiParam.class);
if (apiParam.isPresent()) {
final String allowableValuesString = apiParam.get().allowableValues();
//Your logic here
context.parameterBuilder().allowableValues(allowableValues);
}
}
You need to create constructor in SwaggerConfiguration class.
#Autowire service and withdraw data you need from database
assign this to final variable
assign this final variable to allowableValues in annotation
enjoy not efficient api
private final String allowableValues;
public SwaggerConfiguration() {
List<YourEntitiy> list = someService.findAll();
//code to get every value you need and add create comma separated String
StringJoiner stringJoiner = new StringJoiner(",");
stringJoiner.add(list.get(0).getValue());
this.allowableValues = stringJoiner.toString();
}
#ApiParam(allowableValues = allowableValues)
But I think it's bad idea getting all ids from database just to create allowable values. Just validate in api method if that id exist and/or Create new api to get ids from database, use pagination from Spring Data project, like PageImpl<> javadocs

OOP inheritence, parents variable value not updated on child

this is simple login handler, i never have problem like this when put it on same class. then i try to put it on child class and i don't know what happening.
this is the GUI class
final static Functions.F_Koneksi F_K = new Functions.F_Koneksi();
final static Functions.F_Process F_P = new Functions.F_Process();
final static GUIController F_GUI = new GUIController();
protected javax.swing.JPasswordField jPasswordFieldPasswordLoginPane;
protected javax.swing.JTextField jTextFieldUsernameLoginPane;
...
private void jButtonLoginLoginPaneActionPerformed(java.awt.event.ActionEvent evt) {
switch (F_GUI.DoLogin()) {
case 1:
cl.show(MainPane, "BuyMovie");
break;
...
default:
LoginLabel.setText("username or password ... ");
}
}
and this is the GUIController class
int DoLogin(){
try {
System.err.println(jTextFieldUsernameLoginPane.getText());
char[] PassChars = jPasswordFieldPasswordLoginPane.getPassword();
String Pass = new String(PassChars);
return F_P.F_Login(jTextFieldUsernameLoginPane.getText(), Pass);
} catch (SQLException ex) {
LoginLabel.setText("connection error");
}
return 3;
}
and this is the F_Login method on F_Process
public int F_Login(String User, String Pass) throws SQLException {
ResultSet RS = Select("select * from blablabla"); //this query work already
int level = 8;
if (RS.next()) {
level = RS.getInt("Level");
}
return level;
}
the problem is when i set user and password textfield with right user pass its work but when user put it its not. i know something wrong with my OOP logic but i don't understand where. thank you
this is picture to make you understand what i mean
http://i.stack.imgur.com/1DsrF.png
http://i.stack.imgur.com/uXmGZ.png
Maybe its because the GUIController doesn't access the same jPasswordFieldPasswordLoginPane that the other gui access, to do it, you must pass the object to the GUIController class, like pass the reference in the constructor or setter method, and in the GUIController you access the correct jPasswordFieldPasswordLoginPane.

Not able to set value of instance variable of a class in Java while testing with JUnit

I am trying to test my classes using JUnits and i am facing an issue below is code.
There is a base class BaseMapper and TokenFraming which is dependent class.
The getMappedValue() from the baseclass is calling the mapStates() in the derived class.
I want to set the lineTokenizer instance variable in the TokenFraming class but it is not being set from the code.
When i debug TokenFraming the lineTokenizer is always Null and i get a Null Pointer exception when i try to access the tokenize() method.
I tried setting the value of lineTokenizer by using the setLineTokenizer() but still its not getting set. Also tried to set the value using Reflection but that also does not work. Any ideas as to what i am doing wrong here and how i can correct it. any help would be great.
Class BaseMapper {
private String fieldName;
private String fieldvalue;
// getters and setters
public static String getMappedValue(){
TokenFraming frame = new TokenFraming();
frame.mapStates(fieldName,fieldName,"validate")
}
}
Class TokenFraming {
private Tokenizer lineTokenizer = null;
public void setLineTokenizer(LineTokenizer arg) {
this.lineTokenizer = arg;
}
public String mapStates(String fieldName, String fieldName, String line) {
FieldMappedRow values = this.lineTokenizer.tokenize(line);// NullPointerException here
.......
.......
}
}
JUNit method
#Test
public void testMethods() {
TokenFraming framing = null;
try {
//using reflection to set is not working
framing = new TokenFraming();
Class<?> c1 = framing.getClass();
Field config = c1.getDeclaredField("lineTokenizer ");
config.setAccessible(true);
config.set(framing, new DefaulltToknizer());
//setting with a setter is also not working
framing.setLineTokenizer(new DefaulltToknizer());
BaseMapper mapped = new BaseMapper();
String value = mapped.getMappedValue();
} catch (Exception e) {
message = e.getMessage();
}
Assert.assertNotSame(null, message);
}
The BaseMapper class creates a new instance of TokenFraming - this is not the same instance of TokenFraming that you create in your test.
You should pass the TokenFraming object as an argument:
public static String getMappedValue(TokenFraming frame) {
frame.mapStates(fieldName,fieldName,"validate");
}

Categories

Resources