I'm using some functionality in Java that I don't really understand so I want to read up on it so that I can use it more effectively. The problem is that I don't know what it is called so it makes it difficult to get more information on it:
I have a class Foo defined like this:
private String _name;
private Bar _bar;
//getters and setters
And Bar:
private String _code;
//getters and setters
public String get_isCodeSmith()
{
boolean rVal = _code.toLowerCase().contains("smith");
return rVal;
}
Somehow, in my JSP pages (when I have a Session variable called Foo) I am able to write logic tags like this:
<logic:equal name="Foo" property="_bar._isCodeSmith" value="true">
And even though there is no attribute _isCodeSmith in my class Bar, it runs the get_isCodeSmith() method automatically.
What is this called and where can I find out more?
This is the Javabeans mechanism. Properties are identified not by fields, but by getter (accessor) and / or setter (mutator) methods.
For more technical info, read the JavaBeans spec
Or have a look at this simple test class:
public class TestBean {
private String complete;
public String getComplete() { return complete; }
public void setComplete(final String complete) { this.complete = complete; }
private String getterOnly;
public String getGetterOnly() { return getterOnly; }
private String setterOnly;
public void setSetterOnly(final String setterOnly) { this.setterOnly = setterOnly; }
public String getNoBackingField() { return ""; }
}
and the simple JavaBeans analysis:
public class Test {
public static void analyzeBeanProperties(final Class<?> clazz) throws Exception {
for (final PropertyDescriptor propertyDescriptor
: Introspector.getBeanInfo(clazz, Object.class).getPropertyDescriptors()) {
System.out.println("Property name: " + propertyDescriptor.getName());
System.out.println("Getter method: " + propertyDescriptor.getReadMethod());
System.out.println("Setter method: " + propertyDescriptor.getWriteMethod());
System.out.println();
}
}
public static void main(final String[] args) throws Exception {
analyzeBeanProperties(TestBean.class);
}
}
Output:
Property name: complete
Getter method: public java.lang.String test.bean.TestBean.getComplete()
Setter method: public void test.bean.TestBean.setComplete(java.lang.String)
Property name: getterOnly
Getter method: public java.lang.String test.bean.TestBean.getGetterOnly()
Setter method: null
Property name: noBackingField
Getter method: public java.lang.String test.bean.TestBean.getNoBackingField()
Setter method: null
Property name: setterOnly
Getter method: null
Setter method: public void test.bean.TestBean.setSetterOnly(java.lang.String)
<logic:equal name="Foo" property="a.b.c" value="true">
means Foo.getA().getB().getC()
Doesn't matter if fields exist. Only getters are mandatory.
Related
I apologize if this has been answered before but either i don't know the correct verbiage or my google fu is bad.
I have a TestModel class which has the getters and setters for all the tests I use. Then I have a AdditionalTestModel class that extends the TestModel with additional getters and setters for that specific type of tests.
Now I have BuildTest Class that i want to be able to pass TestModel and any extended classes of TestModel.
public static Class<?> buildTest(Class<?> test, Class<?> template)
throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
Class<?> testClass = test.getClass();
Method[] testMethods = testClass.getMethods();
for (Method method : testMethods) {
String name = method.getName();
if (name.startsWith("get")) {
String testMethodType = method.getReturnType().getTypeName();
// additional code removed//
}
}
If instead of Class<?> i was using TestModel it would work for any test that i pass of Class type TestModel. But i want to be able to pass the extended class to this method as well without having to write a method for each extended class. Any recommendations?
Adding information on the models in case it matters.
public class TestModel {
private String testDescription;
private String testName;
private String apiPath;
private String method;
private String expectedTest;
private Map<String, String> header = new HashMap<>();
private Object body;
private String expectedResult;
private String testCaseId;
private String testUUID;
private List testTypes;
public String getTestDescription() {
return testDescription;
}
public void setTestDescription(String testDescription) {
this.testDescription = testDescription;
}
public String getTestName() {
return testName;
}
public void setTestName(String testName) {
this.testName = testName;
}
public String getAPIPath() {
return apiPath;
}
public void setAPIPath(String apiPath) {
this.apiPath = apiPath;
}
public String getExpectedTest() {
return expectedTest;
}
public void setExpectedTest(String testName) {
this.expectedTest = testName;
}
public String getMethod() {
return method;
}
public void setMethod(String method) {
this.method = method;
}
public Map<String, String> getHeader() {
return header;
}
public void setHeader(Map<String, String> header) {
this.header = header;
}
public Object getBody() {
return body;
}
public void setBody(Object body) {
this.body = body;
}
public String getExpectedResult() {
return expectedResult;
}
public void setExpectedResult(String expectedResult) {
this.expectedResult = expectedResult;
}
public String getTestCaseId() {
return testCaseId;
}
public void setTestCaseId(String testCaseId) {
this.testCaseId = testCaseId;
}
public String getTestUUID() {
return testUUID;
}
public void setTestUUID(String testUUID) {
this.testUUID = testUUID;
}
public List getTestTypes() {
return testTypes;
}
public void setTestTypes(List testTypes) {
this.testTypes = testTypes;
}
}
public class AdditionalTestModel extends TestModel {
#Override public Object getBody() {
return super.getBody();
}
}
Edit: per a request adding the call information here:
#Test(dataProvider = "Default", threadPoolSize = THREADS, timeOut = API_TIME_OUT)
#Description("")
public void sampleTest(AdditionalTestModel testFromDataProvider) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
testSetup(testFromDataProvider);
AdditionalTestModel test = BuildTest.buildTest(testFromDataProvider, template);
Response response = RestAPI.call(test, testEnvironment);
if (null != response) {
ValidateAPIResponse.validateTestModel(test, response);
} else {
Assert.fail("Response is null, probably a bad method.");
}
}
Where testFromDataProvider is passed from a TestNg data provider.
Now LppEdd below already pointed out i could only assign the base class using generics so working on trying it his way, just have not gotten a chance to change things up yet.
Edit: Also realize now my question was bad. Thanks LppEdd. I should have asked How can I get a method to accept an instance of a class and an instance of any extended class
You are close, you just need to use the extends modifier.
If the class passed in as the test and template parameter should be the same exact class type, you can do:
public static <T extends TestModel> Class<T> buildTest(Class<T> test, Class<T> template) { ... }
Otherwise you can do
public static Class<? extends extends TestModel> buildTest(Class<? extends TestModel> test, Class<? extends String> extends TestModel) { ... }
Which will allow different types to be returned and passed in to each parameter.
You can read up on Java generics and wilcards starting here: https://docs.oracle.com/javase/tutorial/java/generics/wildcards.html
Your buildTest method must accept a TestModel class.
You might be looking for something like
public static TestModel buildTest(
final TestModel test,
final TestModel template) {
final Class<? extends TestModel> testClass = test.getClass();
final Method[] testMethods = testClass.getMethods();
for (final Method method : testMethods) {
final String name = method.getName();
if (name.startsWith("get")) {
final String testMethodType = method.getReturnType().getTypeName();
// additional code removed
}
}
// Maybe
return yourNewInstance; // yourNewInstance is a TestModel, or any class extending it
}
The template argument seems unused here (clarify).
What's the wanted return type? (clarify)
Usage example
final TestModel value1 = buildTest(new TestModel(), ...);
final TestModel value2 = buildTest(new AdditionalTestModel(), ...);
This looks to be exactly the same problem as must be solved by test frameworks. For example, see junit (https://junit.org/junit5/).
The core problem is how to obtain the collection of test methods of a class.
A direct solution would be to have the test class be required to answer its test methods, say, Collection<Function<Void, Void>> getTests(); This has several problems, one being that sub-classes must explicitly list their test methods, two being that sub-classes must be careful to add in the test methods from their super-class, and third, this really fits more as static behavior, which would try to shift java instance typing to the class layer, which just isn't supported by java.
An indirect solution would be to require that test methods satisfy a particular pattern (for example, must start with "test" and have no parameters), and use reflection to discover the methods. Or, use an annotation (say, #Test, which is what junit does) to mark out test methods, and again use the java reflection API to discover methods with the marker.
I have a class like this:
public class SampleDto {
private String normalProperty1;
private String normalProperty2;
private String normalProperty3;
private String sensitiveProperty1;
private String sensitiveProperty2;
public String getNormalProperty1() {
return normalProperty1;
}
public void setNormalProperty1(String normalProperty1) {
this.normalProperty1 = normalProperty1;
}
public String getNormalProperty2() {
return normalProperty2;
}
public void setNormalProperty2(String normalProperty2) {
this.normalProperty2 = normalProperty2;
}
public String getNormalProperty3() {
return normalProperty3;
}
public void setNormalProperty3(String normalProperty3) {
this.normalProperty3 = normalProperty3;
}
public String getSensitiveProperty1() {
return sensitiveProperty1;
}
public void setSensitiveProperty1(String sensitiveProperty1) {
this.sensitiveProperty1 = sensitiveProperty1;
}
public String getSensitiveProperty2() {
return sensitiveProperty2;
}
public void setSensitiveProperty2(String sensitiveProperty2) {
this.sensitiveProperty2 = sensitiveProperty2;
}
}
There are parts in the application where i need to serialize it as it is because the object is in a secure environment.
But i need to store the json in a db and store it without the sensitiveProperties, I can't just ignore the properties because they are needed in the other processes.
I was thinking to use Jackson views to solve the problem but i don't know if there is something special in Jackson where I can say, every json object that has the property "sensitiveProperty1" set it to null.
I'm using Java and Jackson
I think that this site covers what you're looking for pretty well.
Essentially what you'll want to do is to add #JsonIgnoreProperties(value = { "intValue" }) at the class level or #JsonIgnore at the field level and then Jackson should take care of the rest for you.
In your case that would look something like:
public class SampleDto {
#JsonIgnore
private String normalProperty1;
private String normalProperty2;
...
Consider the following code:
#Tested
CodeToTest codeToTest;
#Injectable
Injected injected;
#Test
public void test() {
new Expectations() {{ ... }}
assertThat(codeToTest.memberVariable).isEqualTo("x");
}
//
public class CodeToTest { public CodeToTest(Injected injected) { memberVariable = injected.getProperty("x") } }
I want to test CodeToTest. CodeToTest needs Injected to be injected into it's constructor. How do I set a property such as injected.setProperty("x") so that it is available for access in CodeToTest?
The test at hand should be covering a specific method of CodeToTest; the constructor should have its own tests like your test does. So for example, if the constructor is setting a field according to what gets passed in, like this:
public class Bar {
public int getValue() {
return 8675309;
}
}
public class Foo {
public String field = null;
public Foo(Bar b) {
this.field = "" + b.getValue();
}
public String getField() {
return this.field;
}
public char getFirstChar() {
return getField().charAt(0);
}
}
Here I am setting a String field according to an int found in a Bar that was passed into the constructor. I wish to unit test my getFirstChar() method ...
#Tested Foo foo;
#Injectable Bar bar;
#Test
public void test() throws Exception {
// ...
}
Now, as you point out, in this case my field has already been set before test() even starts. So I have two choices here: Firstly, since I am pulling out the field based on its getter, I can partially mock my class being tested:
#Test
public void test() throws Exception {
new Expectations(foo) {{
foo.getField(); result = "24601";
}};
char c = foo.getFirstChar();
assertThat(c, is('2'));
}
OR, if you don't want to do this or if you are doing direct field access rather than via getter, you can use Deencapsulation (part of JMockit) to set the internal field and then test:
#Test
public void test() throws Exception {
Deencapsulation.setField(foo, "field", "24601");
char c = foo.getFirstChar();
assertThat(c, is('2'));
}
And of course, I test my constructor separately:
#Test
public void testConstructor() throws Exception {
new Expectations() {{
bar.getValue(); result = 24601;
}};
Foo foo2 = new Foo(bar);
String fieldValue = foo2.getField(); // or use Deencapsulation
assertThat(fieldValue, is("24601"));
}
Hope this helps, and good luck!
I have my custom annotation, which I am applying to some getters and/or setters.
Not I want some processing. I will find annotated methods and then wish to calculate property name of this method. I.e. I need to cut-out the "get" or "set" or "is" prefix and then do some decapitalization.
Are there some common library like Spring or Apache BeanUtils, which provide all these functions for me?
PFB sample code to get method names having Custom Annotation :
Find Methods with Custom Annotations:
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
public class FindAnnotations {
public static void getAnnotations(Class clazz) {
for (Method method : clazz.getDeclaredMethods()) {
for (Annotation annotation : method.getDeclaredAnnotations()) {
if (annotation.annotationType() == CustomAnnotation.class) {
// do your processing here
String name = method.getName();
System.out.println(name + " : "
+ name.replaceAll("get|set|is", ""));
}
}
}
}
public static void main(String[] args) {
getAnnotations(ChildTest.class);
}
}
ChildTest uses CustomAnnotation:
public class ChildTest {
private String childName;
#CustomAnnotation
public void setChildName(String childName) {
this.childName = childName;
}
#CustomAnnotation
public String getChildName() {
return this.childName;
}
#CustomAnnotation
public boolean isChildName(String childName) {
return true;
}
}
Custom Annotation Class:
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
public #interface CustomAnnotation {
String info() default "";
}
Simple question! I have such a class, and if the attribute is empty (or just null) then this attribute should not appear at all in the generated XML file
XML File: (note empty string in attribute abc, i don't want something like that!)
<root abc="">
<example>somethin</example>
</root>
Java Class
#Root
public class Data {
#Element(name="example">
private String value;
#Attribute(name="abc", required=false)
private String s;
public String getString() {
return s;
}
I tried with a #Convert but it works only with #Element... Is there any way to remove the attribute in the xml file when it is empty?
Use a custom XMLAdapter as such:
public class ExampleAdapter extends XmlAdapter<String, String> {
#Override
public String marshal(String exampleString) throws Exception {
return exampleString;
}
#Override
public String unmarshal(String exampleString) throws Exception {
if (exampleString.isEmpty()) {
return null;
}
return exampleString;
}}
And then just associate your property with it:
#XmlAttribute
#XmlJavaTypeAdapter(ExampleAdapter.class)
public void setExample(String example) {
this.example = example;
}