JavaPath рдЬрдЯрд┐рд▓ рдбреЗрдЯрд╛ рд╕рдВрд░рдЪрдирд╛рдУрдВ рддрдХ рдкрд╣реБрдБрдЪрдиреЗ рдХреЗ рд▓рд┐рдП рд╕реНрдХреНрд░рд┐рдкреНрдЯрд┐рдВрдЧ рднрд╛рд╖рд╛

рд▓реЗрдЦ рдЬрд╛рд╡рд╛ рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдХреЛ рдПрдХ рд╡рд┐рдХрд▓реНрдк рдХреЗ рд░реВрдк рдореЗрдВ рдШреЛрд╖рд┐рдд рдХрд░рддрд╛ рд╣реИ рдФрд░ рдЬрдЯрд┐рд▓ рдбреЗрдЯрд╛ рд╕рдВрд░рдЪрдирд╛рдУрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд╕реНрдЯреИрдВрдб-рдЕрд▓реЛрди рдЕрдиреБрдкреНрд░рдпреЛрдЧреЛрдВ рдореЗрдВ "рд╕реЗрд╡рд╛ рдирд░рдХ" рд╕реЗ рдмрдЪрдиреЗ рдХрд╛ рдПрдХ рддрд░реАрдХрд╛ рд╣реИред


рд╕рдорд╕реНрдпрд╛ рдХрд╛ рд╡рд┐рд╡рд░рдг


рдПрдХ рдЧрд╣рд░реА рдиреЗрд╕реНрдЯреЗрдб рд╕рдВрд░рдЪрдирд╛ рдкрд░ рд╡рд┐рдЪрд╛рд░ рдХрд░реЗрдВ


class A{
   B b;
}
class B{
   C c;
}
class C{
   String name;
}

рдЕрдЧрд░ рд╣рдореЗрдВ рдЗрдВрд╕реНрдЯреЗрдВрд╕ рдП рддрдХ рд╕реАрдзреА рдкрд╣реБрдВрдЪ рдХреЗ рдмрд┐рдирд╛ рдХреНрд▓рд╛рд╕ рд╕реА рдХреЗ рдирд╛рдо рдХреНрд╖реЗрддреНрд░ рдХреЗ рд▓рд┐рдП рдПрдХ рдорд╛рди рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рддреЛ рд╕реЗрд╡рд╛ рдПрдкреАрдЖрдИ рдХреА рдПрдХ рдордзреНрдпрд╡рд░реНрддреА рдкрд░рдд рдЖрдорддреМрд░ рдкрд░ рдмрдЪрд╛рд╡ рдХреЗ рд▓рд┐рдП рдЖрддреА рд╣реИред


private A a;
public void setNameService(String name) {
    a.b.c.name = name;
}

, , . , .


private A a;
public void setNameService(String name) {
    if(a == null) {
        a = new A();
    }
    if(a.b == null) {
        a.b = new B();
    }
    if(a.b.c == null) {
        a.b.c = new C();
    }
    a.b.c.name = name;
}

, , setNameService(String name) , , a, b c, , .


API, , , API. . , . , , 'C' name, 'B' 'A' .


, - . , , , . - - . , . , , , , .


JavaPath , .


JavaPath


JavaPath.


private A a = new A();
private final JavaPath javaPath = new JavaPath(A.class);

public void setNameService(String name) {
    javaPath.evalPath("b.c.name", a, name);
}

setNameService.


, JavaPath тАФ , Java. JavaPath . , . JavaPath . -public. . JavaPath private final .


: тАФ JavaPath!


final String str = "VALUE";
JavaPath javaPath = new JavaPath(String.class);
assertEquals("VALUE",str);
//  private final byte[] value;  String 
javaPath.evalPath("value",str,"THE HACK".getBytes());
assertEquals("THE HACK",str);

- , , JavaPath Java Reflection .


, JavaPath . . .


JavaPath


public Object evalPath(String path, Object root, Object... values);

evalPath


  • тАФ Java
  • A тАФ b
  • , . тАФ тАФ name

, . C. .


class C{
    String name;
    public void setName(String name) {
        this.name = name;
    }   
}

. .


A a = new A();
JavaPath javaPath = new JavaPath(A.class);
public void setNameService(String name) {
    javaPath.evalPath("b.c.setName", a, name);
}

JavaPath , , , :


    javaPath.evalPath("b.c.setName($)", a, name);

$ $0 тАФ .



a0.a1.тАж .an



a0.a1.тАж .an-1


, , / null. an . , , , evalPath. , . JavaPath .


JavaPath


JavaPath , . . . , , , . , , ,
Java . , , , API.



рд╕рд┐рдВрдЯреЗрдХреНрд╕ рдЪрд╛рд░реНрдЯ



JavaPath . . , , , . . , , , .. тАФ .


$ #


рд╡рд┐рд╢реЗрд╖ рдкреИрд░рд╛рдореАрдЯрд░



, evalPath $[:digit:]* . $ , . .


.


JavaPath
"a($)",
"a($0)"
"a($1.name)"name,


. : #[:digit:]* # #0


.


JavaPath
"a(#)"
"a(#0.name)"name
"a.b(#1)"'a'

, -.


public class A {
    A parent;
    A child;
    String name;
    public A(A parent) {
        this.parent = parent;
    }
}

A a = new A(null);
JavaPath javaPath = new JavaPath(A.class);
javaPath.evalPath("name",a,"PARENT");
javaPath.evalPath("child(#0).name",a,"CHILD");
javaPath.evalPath("child(#0).child(#1).name",a,"GRAND-CHILD");
assertEquals("PARENT",a.name);
assertEquals("CHILD",a.child.name);
assertEquals("GRAND-CHILD",a.child.child.name);
assertEquals("CHILD",a.child.child.parent.name);
assertEquals("PARENT",a.child.child.parent.parent.name);

тАФ .


"a.set('$0')" //  $0

InLine :


, JavaPath. , , . .


JavaPath
"a.b.c". , evalPath , .
"a.b.c($)", .
"a.b.c($0)"$0 $ .
"a.b.c('THE VALUE')"c 'THE VALUE' evalPath . .
"a().b().c",
"a().b.c".
"a.b(int 1024).c"
"a.b(Int 1024).c"Integer
"a.b(int 1024,' ').c",
a.setX(PhoneType CELL)enum PhoneType{HOME,CELL,WORK}, "CELL"

, , valueOf ( , enum ) .


, valueOf - , StringConverter, .



- null , . .


, , , . тАФ . Java, .


"(T a).b"

: map .


public class A {
    Map<String,String> map;
}

A a = new A();
JavaPath javaPath = new JavaPath(A.class);
//       map
javaPath.evalPath("(HashMap map).put(firstName,$)", a, "John");
//    ,     .
javaPath.evalPath("map.put(lastName,$)", a, "Silver");

.


//  HashMap      .
//        0.8 
javaPath.evalPath("(HashMap map(int 100,float '0.8')).put(firstName,$)", a, "John");

, null. map .



enum PhoneType{HOME,CELL,WORK}
public static class A {
    String firstName;
    String lastName;
    Map<PhoneType, Set<String>> phones;
    Map<String, PhoneType> reversedPhones;
}

A a = new A();
ClassRegistry  classRegistry = new ClassRegistry();
classRegistry.registerClass(PhoneType.class,PhoneType.class.getSimpleName());
JavaPath javaPath = new JavaPath(A.class,classRegistry);

javaPath.evalPath("(map phones).put(PhoneType WORK)", a, new HashSet<>());
javaPath.evalPath("phones.computeIfAbsent(PhoneType HOME,key->new HashSet).@", a);
javaPath.evalPath("phones.computeIfAbsent(PhoneType CELL,key->new HashSet).@", a);
javaPath.evalPath("(map reversedPhones).@", a);

javaPath.evalPath("firstName", a, "John");
javaPath.evalPath("lastName", a, "Smith");

javaPath.evalPath("phones.get(PhoneType CELL).add", a, "1-101-111-2233");
javaPath.evalPath("phones.get(PhoneType HOME).add", a, "1-101-111-7865");
javaPath.evalPath("phones.get(PhoneType WORK).add", a, "1-105-333-1100");
javaPath.evalPath("phones.get(PhoneType WORK).add($)", a, "1-105-333-1104");

javaPath.evalPath("reversedPhones.put($,PhoneType CELL)", a, "1-101-111-2233");
javaPath.evalPath("reversedPhones.put($,PhoneType HOME)", a, "1-101-111-7865");
javaPath.evalPath("reversedPhones.put($,PhoneType WORK)", a, "1-105-333-1100");
javaPath.evalPath("reversedPhones.put($,PhoneType WORK)", a, "1-105-333-1104");

@


@ . , . .


||


null, JavaPath . .


JavaPath
"getAтИгтИгsetA($1).name($0)"getA null setA, getA
"getAтИгтИгinit.name($0)"

::


, -, ::


JavaPath
"(UserInfo::newInstance userInfo).phone.ext"UserInfo UserInfo.newInstance()
"(UserInfo::newInstance userInfo(John,Smith)).phone.ext"UserInfo UserInfo.newInstance(String a, String b)
"a.b(Integer::valueOf 100).c". .
"(HashMap::new map).get"- new . .

ClassRegistry


, , .. ClassRegistry , JavaPath.


ClassRegistry . ClassRegistry, JavaPath.


PhoneType


ClassRegistry  classRegistry = new ClassRegistry();
classRegistry.registerClass(PhoneType.class,PhoneType.class.getSimpleName(),"Phone");
JavaPath javaPath = new JavaPath(A.class,classRegistry);

PhoneType , , Phone.


ClassRegistry . , :: .


. ClassRegistry . , StringConverter тАФ .


public class A {
...
static {
    ClassRegistry.registerGlobalStringConverter(A.class,A::stringToA); 
}
public static A stringToA(String str) {
       A a = new A("{"+str+"}"); // - 
       return a;
    }
}

public class B {
    A a;
}

JavaPath javaPath = new JavaPath(B.class); //  A::stringToA

@PathElement @NoPathElement


@PathElement .


public class A {
    String name; //       "name"
    @PathElement({"name","first_name","firstName"})
    public void setName(String name) {
        this.name = name;
    }
}

, setName "name", . .


@NoPathElement JavaPath.


public class A {
    StringBuilder stringBuilder = new StringBuilder();

    @NoPathElement
    private final String protectedField = "IMMUTABLE BY JAVA PATH!";

    public void add(String str) {
        stringBuilder.append(str == null ? "N/A" : str);
    }

    @NoPathElement
    public void add(Object val) {
        stringBuilder.append(val);
    }
}

.





JavaPath . .


public class A {
    String firstName;
    String lastName;
    int age;
}

A a = new A();
JavaPath javaPath = new JavaPath(A.class);
javaPath.evalPath("firstName; lastName; age", a, "John","Smith",55);
// $       ,    
javaPath.evalPath("firstName($); lastName($); age($)", a, "John","Smith",55);
//         .
javaPath.evalPath("firstName($0); lastName($1); age($2)", a, "John","Smith",55);

'$', , . , firstName($) "John" ( , ), age($) тАФ 55 ( , ). .


, , .


. .




JavaPath


, . , ? initPath
.


JavaPath . , . , , root. # #0


initPath .


:


//      JavaPath.  
Object instanceOfA = javaPath.initPath("(com.my.project.A #0).b", "test");
//      initPath
A instanceOfA = javaPath.initPath(A.class, "#.b", "test");
//       , #  #0
A instanceOfA = javaPath.initPath(A.class, "root.b", "test");




JavaPath рд╡рд░реНрдЧ рдХреА setEnablePathCaching (рдмреВрд▓рд┐рдпрди рдЗрдиреЗрдмрд▓ рдХреЛрдЪрд┐рдВрдЧ) рд╡рд┐рдзрд┐ рдЖрдкрдХреЛ рдкрд╛рд░реНрд╕рд░ рдХреЗ рдкрд░рд┐рдгрд╛рдо рдХреЛ рдХреИрд╢ рдореЗрдВ рд╕рд╣реЗрдЬрдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддреА рд╣реИред рдлрд╝реАрд▓реНрдб рдкрджрд╛рдиреБрдХреНрд░рдо рдФрд░ рд╡рд░реНрдЧ рд╡рд┐рдзрд┐рдпреЛрдВ рдХреЗ рдЧреИрд░-рдирд┐рд╖реНрдХреНрд░рд┐рдп рдХреИрд╢рд┐рдВрдЧ рдХреЗ рд╕рд╛рде рднреНрд░рдорд┐рдд рдирд╣реАрдВ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдПред рдкрде рдХреИрд╢ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд░реВрдк рд╕реЗ рдЕрдХреНрд╖рдо рд╣реИ рдХреНрдпреЛрдВрдХрд┐ рдпрд╣ рдЕрдирд┐рдпрдВрддреНрд░рд┐рдд рдореЗрдореЛрд░реА рдЦрдкрдд рдХрд╛ рдХрд╛рд░рдг рдмрди рд╕рдХрддрд╛ рд╣реИ рдпрджрд┐ рдкрде рдЧрддрд┐рд╢реАрд▓ рд░реВрдк рд╕реЗ рдЧрдгрдирд╛ рдХреА рдЬрд╛рддреА рд╣реИред


рдЙрджрд╛рд╣рд░рдг - рдХреИрд╢ рдореЗрдВ рддреАрди рдЕрд▓рдЧ-рдЕрд▓рдЧ рд░рд╛рд╕реНрддреЗ рд╣реЛрдВрдЧреЗ:


evalPath("user.name('John'));"
evalPath("user.name('Peter'));"
evalPath("user.name('Mike'));"

рдЗрд╕рдХреЗ рдмрдЬрд╛рдп, рд╕реНрдкрд╖реНрдЯ рд░реВрдк рд╕реЗ рдЧреБрдЬрд░ рдЪрд░ рдорд╛рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВред рдиреАрдЪреЗ рдХрд╛ рдЙрджрд╛рд╣рд░рдг рдПрдХ рд░рд╛рд╕реНрддрд╛ рдмрдЪрд╛рдПрдЧрд╛ред


evalPath("user.name($0)","John");
evalPath("user.name($0)","Peter");
evalPath("user.name($0)","Mike");

рдирд┐рд░реНрднрд░рддрд╛


Java8 рдФрд░ рдкреБрд░рд╛рдиреЗ


рдорд╛рд╡реЗрди рднрдВрдбрд╛рд░


<dependency>
    <groupId>com.aegisql</groupId>
    <artifactId>java-path</artifactId>
    <version>0.2.0</version>
</dependency>

All Articles