Class for easy generation of xpaths - java

I would like to write a class for generating xpaths. The class should have 2 methods: down(String string) and child(String string).
I would like to use the class like that:
XpathBuilder.child("div").down("button").child("a").child("span")
//That should return a String: div//button/a/span
Could anybody suggest me how can I do that?

You could take a look at builder pattern.
Here is one example (uses internal builder class):
public class XpathBuilder {
public Builder builder() {
return new XpathBuilder.Builder();
}
class Builder {
private final StringBuilder sb;
Builder() {
sb = new StringBuilder();
}
public Builder child(String name) {
sb.append("/").append(name);
return this;
}
public Builder down(String name) {
sb.append("//").append(name);
return this;
}
public String build() {
return sb.toString();
}
}
}
It can be called like this:
String path = new XpathBuilder().builder().child("div").down("button").child("a").child("span").build();
Here is another example (uses builder as well as singleton pattern):
public class XpathBuilder {
private final StringBuilder sb;
private static XpathBuilder instance;
private XpathBuilder() {
sb = new StringBuilder();
}
public static XpathBuilder newInstance() {
if (instance == null) {
instance = new XpathBuilder();
}
return instance;
}
public XpathBuilder child(String name) {
sb.append("/").append(name);
return this;
}
public XpathBuilder down(String name) {
sb.append("//").append(name);
return this;
}
public String build() {
return sb.toString();
}
}
It can be called like this:
String path = XpathBuilder.newInstance().child("div").down("button").child("a").child("span").build();

I think I found an easier solution overriding the toString method from the class Object. Doing that I need only one class:
public class XpathBuilder {
StringBuilder sb = new StringBuilder();
public XpathBuilder child(String string) {
sb.append("/"+string);
return this;
}
public XpathBuilder down(String string){
sb.append("//"+string);
return this;
}
#Override
public String toString(){
return sb.toString();
}

Related

Java send class parameters by only one object

It is possible to create an Object as "only for parameters"?. For example:
class MyClass {
public String a;
public Number b;
public MyClass(Object params) {
this.a = params.a !== null ? params.a : "default";
this.b = params.b !== null ? params.b : 0;
}
}
void main() {
MyClass myclass1 = new MyClass(new Object() {
String a = "hey";
});
MyClass myclass2 = new MyClass(new Object() {
Number b = 123;
});
MyClass myclass3 = new MyClass(new Object() {
String a = "!!!";
Number b = 5;
});
}
Obviously this code doesn't work, I tried a lot of ways trying to replicate it, maybe with Templates (Generic)?
The expected results will be:
myclass1.a == "hey";
myclass1.b == 0;
myclass2.a == "default";
myclass2.b == 123;
myclass3.a == "!!!";
myclass3.b == 5;
You could use a Builder pattern to create required instance:
public final class MyClass {
private final String str;
private final Number number;
public static Builder builder() {
return new Builder();
}
private MyClass(Builder builder) {
str = builder.str;
number = builder.number;
}
public String getStr() {
return str;
}
public Number getNumber() {
return number;
}
public static final class Builder {
private String str = "default";
private Number number = 0;
private Builder() {
}
public MyClass build() {
return new MyClass(this);
}
public Builder str(String str) {
this.str = str;
return this;
}
public Builder number(Number number) {
this.number = number;
return this;
}
}
}
Demo:
public static void main(String... args) {
MyClass myclass1 = MyClass.builder().str("hey").build();
MyClass myclass2 = MyClass.builder().number(123).build();
MyClass myclass3 = MyClass.builder().str("!!!").number(5).build();
}
In case you do not want to use Builder pattern, you could use class override:
public class MyClass {
public String getStr() {
return "default";
}
public Number getNumber() {
return 0;
}
}
public static void main(String... args) throws IOException {
MyClass myclass1 = new MyClass() {
#Override
public String getStr() {
return "hey";
}
};
MyClass myclass2 = new MyClass() {
#Override
public String getStr() {
return "hey";
}
#Override
public Number getNumber() {
return 123;
}
};
MyClass myclass3 = new MyClass() {
#Override
public String getStr() {
return "!!!";
}
#Override
public Number getNumber() {
return 5;
}
};
}

Issue With #JsonProperty on Method

I currently have my POJO class as such for deserializing a json source.
public class OpenBuilding extends Building {
#JsonProperty("BuildingPostCode")
#Override
public String getPostcode() {
return super.getPostcode();
}
}
Where the parent class is as such
public abstract class Buidling {
protected String postcode;
public String getPostcode() {
return this.postcode;
}
}
My issue is that the String postcode isn't getting mapped at all. It works when using the annotation on the field. However since it is an inherited field and I have other children of Building, which use different property names for the same data, I cannot have it implemented in that way.
For example:
public class DirectedBuilding extends Building {
#JsonProperty("Pseudo_PostCode")
#Override
public String getPostcode() {
return super.getPostcode();
}
}
Perhaps try defining a constructor with #JsonCreator.
class Parent {
private final String foo;
public Parent(final String foo) {
this.foo = foo;
}
public String getFoo() {
return foo;
}
}
class Child extends Parent {
#JsonCreator
public Child(#JsonProperty("foo") final String foo) {
super(foo);
}
#JsonProperty("foo")
public String getFoo() {
return super.getFoo();
}
}
public static void main(String[] args) throws Exception {
final ObjectMapper objectMapper = new ObjectMapper();
final Child toSerialize = new Child("fooValue");
// Serialize the object to JSON
final String json = objectMapper.writer()
.withDefaultPrettyPrinter()
.writeValueAsString(toSerialize);
// Prints { "foo" : "fooValue" }
System.out.println(json);
// Deserialize the JSON
final Child deserializedChild = objectMapper.readValue(json, Child.class);
// Prints fooValue
System.out.println(deserializedChild.getFoo());
}

How to protect private field in class with getter in java

I have the following code.
public class GetterTest {
public static void main(String[] args) {
Car car = new Car();
StringBuilder wheel = car.getWheel();
wheel.append("asd");
System.out.println(car.getWheel());
}
}
class Car {
private StringBuilder wheel;
public Car() {
wheel = new StringBuilder("a");
}
public StringBuilder getWheel() {
return wheel;
}
public void setWheel(StringBuilder wheel) {
this.wheel = wheel;
}
}
The problem here is even I have a getter it don't protect the variable and it is changed after using it. How to protect the variable better?
You shouldn't return the StringBuilder but rather the value. This creates a new String which isn't connected to your backing StringBuilder anymore.
public String getWheel() {
return wheel.toString();
}
However if you really want to return a StringBuilder, you can create a new one with the current one's data, essentially disconnecting both instances:
public StringBuilder getWheel() {
return new StringBuilder(wheel.toString());
}
A StringBuilder variable is not a good candidate for a getter. It would make more sense to have a getter that returns the current String value of that StringBuilder, since a String it immutable :
public String getWheel() {
return wheel.toString();
}
The setter should also be changed, since the current impl allows the caller of the setter to mutate the StringBuilder that was passed to the setter, and thus mutate the member after the setter is called.
public void setWheel (String wheel)
{
this.wheel = new StringBuilder (wheel);
}
In the field's that you want to protect getter you can clone the field instead of returning the current field.
public void doSomething() {
Car car = new Car();
Wheel wheel = car.getWheel();
wheel.getaVariable().append("asd");
System.out.println(car.getWheel());
}
public class Car {
private Wheel wheel;
public Car() {
wheel = new Wheel();
}
public Wheel getWheel() {
Wheel output = null;
try {
output = wheel.clone();
} catch (CloneNotSupportedException e) {
// Manage exception
}
return output;
}
public void setWheel(Wheel wheel) {
this.wheel = wheel;
}
}
public class Wheel implements Cloneable {
private StringBuilder aVariable;
public Wheel() {
aVariable = new StringBuilder("a");
}
public StringBuilder getaVariable() {
return aVariable;
}
public void setaVariable(StringBuilder aVariable) {
this.aVariable = aVariable;
}
#Override
protected Wheel clone() throws CloneNotSupportedException {
Wheel clone = (Wheel) super.clone();
clone.setaVariable(new StringBuilder(aVariable));
return clone;
}
#Override
public String toString() {
return aVariable.toString();
}
}

Using Builder Constructor on Extended Class?

I'm implementing a Builder constructor as documented in Joshua Bloch's "Effective Java 2nd Edition. However, I'm running into a few complications when I try to extend the class and its builder. Essentially, the extended Builder in the extended child class has set field methods that return the parent Builder type, not the child builder type.
Of course, I can cast back to the ChildBuilder in the property build chain (as shown in my main method) but it is not seamless which defeats the purpose of the Builder, and it also forces me to segregate the parent setters and child setters.
I tried to use generics but it ended up becoming more verbose than the cast.
Is there a way I can consistently make the set methods on the builders return the builder type that was actually instantiated?
public class ParentObj {
public static void main(String[] args) {
ChildObj childObj = ((ChildObj.ChildBuilder) (new ChildObj.ChildBuilder())
.prop1(11)
.prop2(21)
.prop3(14))
.prop4(12)
.prop5(33)
.build();
}
private int prop1;
private int prop2;
private int prop3;
protected ParentObj(Builder builder) {
this.prop1 = builder.prop1;
this.prop2 = builder.prop2;
this.prop3 = builder.prop3;
}
public class Builder {
private int prop1;
private int prop2;
private int prop3;
public Builder prop1(int prop1) { this.prop1 = prop1; return this; }
public Builder prop2(int prop2) { this.prop2 = prop2; return this; }
public Builder prop3(int prop3) { this.prop3 = prop3; return this; }
public ParentObj build()
{
return new ParentObj(this);
}
}
}
private class ChildObj extends ParentObj {
private final int prop4;
private final int prop5;
private ChildObj(ChildBuilder childBuilder) {
super(childBuilder);
}
public class ChildBuilder extends Builder {
private int prop4;
private int prop5;
public ChildBuilder prop4(int prop4) { this.prop4 = prop4; return this; }
public ChildBuilder prop5(int prop5) { this.prop5 = prop5; return this; }
public ChildObj build() {
return new ChildObj(this);
}
}
}
Probably the best way would be to Override the parent builder methods.
class ChildBuilder {
public ChildBuilder prop1(int prop1){
return (ChildBuilder) super.prop1(prop1);
}
}
While this isn't exactly clean it will work for what you're trying to do.

Java Generics in Builder

How can I use generics propery in my particular case? The code first, then the explanation:
AbstractConstraint.java
public abstract class AbstractConstraint {
public abstract Constraint[] getConstraints();
}
AccountConstraint.java
public class AccountConstraint extends AbstractConstraint {
private Constraint<Range<Integer>> accountIdConstraint;
private Constraint<String> usernameConstraint;
private Constraint<String> passwordConstraint;
private Constraint<String> emailConstraint;
private AccountConstraint(Builder builder) {
this.accountIdConstraint = builder.accountIdConstraint;
this.usernameConstraint = builder.usernameConstraint;
this.passwordConstraint = builder.passwordConstraint;
this.emailConstraint = builder.emailConstraint;
}
#Override
public Constraint[] getConstraints() {
return new Constraint[] {
this.accountIdConstraint,
this.usernameConstraint,
this.passwordConstraint,
this.emailConstraint
};
}
public static class Builder extends ConstraintBuilder<AccountConstraint> {
private Constraint<Range<Integer>> accountIdConstraint;
private Constraint<String> usernameConstraint;
private Constraint<String> passwordConstraint;
private Constraint<String> emailConstraint;
public Builder() {
this.accountIdConstraint = null;
this.usernameConstraint = null;
this.passwordConstraint = null;
this.emailConstraint = null;
init();
}
public Builder accountId(final int val) {
this.accountIdConstraint = new Constraint<>(operation, truthed, new Range<>(val), "accountId");
return this;
}
public Builder accountId(final int min, final int max) {
this.accountIdConstraint = new Constraint<>(operation, truthed, new Range<>(min, max), "accountId");
return this;
}
public Builder accountId(final Range<Integer> accountId) {
this.accountIdConstraint = new Constraint<>(operation, truthed, accountId, "accountId");
return this;
}
public Builder username(final String username) {
this.usernameConstraint = new Constraint<>(operation, truthed, username, "username");
return this;
}
public Builder email(final String email) {
this.emailConstraint = new Constraint<>(operation, truthed, email, "email");
return this;
}
#Override
public AccountConstraint build() {
return new AccountConstraint(this);
}
}
}
ConstraintBuilder.java
public abstract class ConstraintBuilder<T> {
protected boolean truthed;
protected Operation operation;
protected void init() {
truthed = true;
operation = Operation.IS;
}
public ConstraintBuilder not() {
truthed = false;
return this;
}
public ConstraintBuilder like() {
operation = Operation.LIKE;
return this;
}
public abstract T build();
}
I want to be able to call new AccountConstraint.Builder().not().username("test"); but this is not possible as I lose the 'reference to the builder' at new AccountConstraint.Builder().not()., ie. I cannot select username("test") anymore.
In what ways could I fix this? I do want that the AccountBuilder.Builder extends ConstraintBuilder<AccountConstraint.Builder> such that I do not have to duplicate the commonly shared methods then.
Regards.
EDIT: I managed to get it working:
See the answer below for the changes.
I hope I haven't broken any Java fundamentals with this solution, I hope it is more of a solution than a dirty hack.
I would be pleased if someone could review this edit.
I think this should work:
Builder builder = (Builder) new AccountConstraint.Builder().not();
builder = builder.username("test");
Your issue is that:
new AccountConstraint.Builder().not()
returns a ConstrainBuilder<T>, which doesn't necessarily have access to username(final String). So, you cast it to a Builder builder, and then call username(final String) on builder.
EDIT:
You can turn this into one line:
((Builder) (new AccountConstraint.Builder().not())).username("test");
EDIT 2:
You could override not() in Builder: make it call super.not() and cast the return to a Builder. As in:
public Builder not()
{
return (Builder) super.not();
}
If casting is acceptable, an alternative to Steve's answer would be to override methods like not() in Builder and narrow the type like this:
public Builder not() {
return (Builder) super.not();
}
That way the caller doesn't have to cast each time.
You probably need recursive generics.
Something like this should work:
public abstract class ConstraintBuilder<T, B extends ConstraintBuilder<T,B>> {
private final Class<B> concreteBuilderType;
public ConstraintBuilder(Class<B> concreteBuilderType) {
if (!concreteBuilderType.isInstance(this)) {
throw new IllegalArgumentException("Wrong type");
}
this.concreteBuilderType = concreteBuilderType;
}
...
public B not() {
truthed = false;
return concreteBuilderType.cast(this);
}
}
The concrete Builder() constructor would have to call super(Builder.class).

Categories

Resources