Categories
discuss

Spring Data JPA Specification using CriteriaBuilder with a one to many relationship

I have a User entity, a UserToApplication entity, and an Application entity.

A single User can have access to more than one Application. And a single Application can be used by more than one User.

Here is the User entity.

@Entity
@Table(name = "USER", schema = "UDB")
public class User {
    private Long userId;
    private Collection<Application> applications;
    private String firstNm;
    private String lastNm;
    private String email;

    @SequenceGenerator(name = "generator", sequenceName = "UDB.USER_SEQ", initialValue = 1, allocationSize = 1)
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "generator")
    @Column(name = "USER_ID", unique = true, nullable = false)
    public Long getUserId() {
        return userId;
    }

    public void setUserId(Long userId) {
        this.userId = userId;
    }

    @OneToMany(mappedBy = "user", fetch = FetchType.LAZY)
    public Collection<Application> getApplications() {
        return applications;
    }

    public void setApplications(Collection<Application> applications) {
        this.applications = applications;
    }

    /* Other getters and setters omitted for brevity */
}

Here is the UserToApplication entity.

@Entity
@Table(name = "USER_TO_APPLICATION", schema = "UDB")
public class Application {
    private Long userToApplicationId;
    private User user;
    private Application application;

    @SequenceGenerator(name = "generator", sequenceName = "UDB.USER_TO_APP_SEQ", initialValue = 0, allocationSize = 1)
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "generator")
    @Column(name = "USER_TO_APPLICATION_ID", unique = true, nullable = false)
    public Long getUserToApplicationId() {
        return userToApplicationId;
    }

    public void setUserToApplicationId(Long userToApplicationId) {
        this.userToApplicationId = userToApplicationId;
    }

    @ManyToOne
    @JoinColumn(name = "USER_ID", referencedColumnName = "USER_ID", nullable = false)
    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    @ManyToOne
    @JoinColumn(name = "APPLICATION_ID", nullable = false)
    public Application getApplication() {
        return application;
    }
}

And here is the Application entity.

@Entity
@Table(name = "APPLICATION", schema = "UDB")
public class Application {
    private Long applicationId;
    private String name;
    private String code;

    /* Getters and setters omitted for brevity */
}

I have the following Specification that I use to search for a User by firstNm, lastNm, and email.

public class UserSpecification {

    public static Specification<User> findByFirstNmLastNmEmail(String firstNm, String lastNm, String email) {
        return new Specification<User>() {
            @Override
            public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                final Predicate firstNmPredicate = null;
                final Predicate lastNmPredicate = null;
                final Predicate emailPredicate = null;

                if (!StringUtils.isEmpty(firstNm)) {
                    firstNmPredicate = cb.like(cb.lower(root.get(User_.firstNm), firstNm));
                }
                if (!StringUtils.isEmpty(lastNm)) {
                    lastNmPredicate = cb.like(cb.lower(root.get(User_.lastNm), lastNm));
                }
                if (!StringUtils.isEmpty(email)) {
                    emailPredicate = cb.like(cb.lower(root.get(User_.email), email));
                }
                return cb.and(firstNmPredicate, lastNmPredicate, emailPredicate);
            }
        };
    }

}

And here is the User_ metamodel that I have so far.

@StaticMetamodel(User.class)
public class User_ {
    public static volatile SingularAttribute<User, String> firstNm;
    public static volatile SingularAttribute<User, String> lastNm;
    public static volatile SingularAttribute<User, String> email;
}

Now, I would like to also pass in a list of application IDs to the Specification, such that its method signature would be:

public static Specification<User> findByFirstNmLastNmEmailApp(String firstNm, String lastNm, String email, Collection<Long> appIds)

So, my question is, if I add the @OneToMany mapping to the User_ metamodel for the Collection<Application> applications field of my User entity, then how would I reference it in the Specification?

My current Specification would be similar to the following SQL query:

select * from user u
where lower(first_nm) like '%firstNm%'
and lower(last_nm) like '%lastNm%'
and lower(email) like '%email%';

And what I would like to achieve in the new Specification would be something like this:

select * from user u
join user_to_application uta on uta.user_id = u.user_id
where lower(u.first_nm) like '%firstNm%'
and lower(u.last_nm) like '%lastNm%'
and lower(u.email) like '%email%'
and uta.application_id in (appIds);

Is it possible to do this kind of mapping in the metamodel, and how could I achieve this result in my Specification?

Answer

I found a solution. To map a one to many attribute, in the metamodel I added the following:

public static volatile CollectionAttribute<User, Application> applications;

I also needed to add a metamodel for the Application entity.

@StaticMetamodel(Application.class)
public class Application_ {
    public static volatile SingularAttribute<Application, Long> applicationId;
}

Then in my Specification, I could access the applications for a user, using the .join() method on the Root<User> instance. Here is the Predicate I formed.

final Predicate appPredicate = root.join(User_.applications).get(Application_.applicationId).in(appIds);

Also, it is worth noting that my Specification as it is written in the question will not work if any of the input values are empty. A null Predicate passed to the .and() method of CriteriaBuilder will cause a NullPointerException. So, I created an ArrayList of type Predicate, then added each Predicate to the list if the corresponding parameter was non-empty. Finally, I convert the ArrayList to an array to pass it to the .and() function of the CriteriaBuilder. Here is the final Specification:

public class UserSpecification {

    public static Specification<User> findByFirstNmLastNmEmailApp(String firstNm, String lastNm, String email, Collection<Long> appIds) {
        return new Specification<User>() {
            @Override
            public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                final Collection<Predicate> predicates = new ArrayList<>();
                if (!StringUtils.isEmpty(firstNm)) {
                    final Predicate firstNmPredicate = cb.like(cb.lower(root.get(User_.firstNm), firstNm));
                    predicates.add(firstNmPredicate);
                }
                if (!StringUtils.isEmpty(lastNm)) {
                    final Predicate lastNmPredicate = cb.like(cb.lower(root.get(User_.lastNm), lastNm));
                    predicates.add(lastNmPredicate);
                }
                if (!StringUtils.isEmpty(email)) {
                    final Predicate emailPredicate = cb.like(cb.lower(root.get(User_.email), email));
                    predicates.add(emailPredicate);
                }
                if (!appIds.isEmpty()) {
                    final Predicate appPredicate = root.join(User_.applications).get(Application_.applicationId).in(appIds);
                    predicates.add(appPredicate);
                }

                return cb.and(predicates.toArray(new Predicate[predicates.size()]));
            }
        };
    }

}
Categories
discuss

RethinkDB JavaScript Date Filter

I’m trying to query only things that are less than a day old… in JS this returns true; Why is rethink not returning true, so also not returning any results?

r.db( "db" ).table("table")
  .filter( function (item) {
    var
        now = new Date(),
        then = new Date( item.upload_date );
    return now - then > 1000*60*60*24
  });

I’ve tried this as well:

r.db( "db" ).table("table")
  .filter( function (item) {
    var
        now = new Date(),
        then = new Date( item( "upload_date") );
    return now - then > 1000*60*60*24
  });

EDIT: It’s definitely my item( "upload_date" ) is not returning the date string… what should I be using there instead?

Answer

ReQL is smart enough to parse strings and sort them. If you have your date in the correct format it should still filter with an .lt on the row.

r.db("database").table("table")
    .filter( r.row('upload_date')
    .lt( new Date( new Date() - (24*60*60*1000) ).toISOString().replace(/..{4}/, '').replace(/T/, ' ') ) )


Cheers

–EDIT–

( For learning or testing use Regex101.com )

Requested Regular Expression in String.replace() method:

FIRST – ( Dump the end of the time code )

eg: “2017-03-20T17:17:37.966Z” -> “2017-03-20T17:17:37”

  • Find the first literal period. .
  • -> And ANY 4 characters after that.{4}

Replace the above group them with empty quote, or nothing

SECOND

eg: “2017-03-20T17:17:37” -> “2017-03-20 17:17:37”

  • Find the first instance of the character T

Replace above group with a space character or ” “

This sets the string to be able to compare inside rethink db

NOTICE: RethinkDB as a project has been dropped, but will be open sourced. Consider other resources for your projects if you require support.

Categories
discuss

Change hint text on AppCompatEditText at runtime?

Has anyone figured out a way to change the hint text (the text displayed when the field is empty) at runtime instead of in the layout? The layout looks like this:

      <android.support.design.widget.TextInputLayout
          style="@style/CreateAccount.Zip.Label">
          <android.support.v7.widget.AppCompatEditText
              android:id="@+id/Zip"
              style="@style/CreateAccount.Zip" />
      </android.support.design.widget.TextInputLayout>

The problem I have is that the Material Design field label animation gets broken if I set it at runtime 🙁 It just stays static if I set it at runtime…no motion at all when you start typing.

Answer

You have to change the TextInputLayout hint:

TextInputLayout textInputLayout = (TextInputLayout) findViewById(R.id.my_text_input_layout);
textInputLayout.setHint("New hint");
Categories
discuss

What exactly happens when thread enters a synchronized block / method in Java

I’m curious what happens underneath when my thread gets to a synchronized block and blocks the monitor.

Does it actually call wait() implicitly on all other threads that try to use this monitor? Or the monitor has some specific flags that being changed?

Also, what happens when we get out of the synchronized block? Does it somehow call notify or notifyAll for current monitor?

I am really tangled up about this.

Answer

I think it is best to think in terms of underlying synchronization primitives: a java monitor is a mutex, a synchronized block is a region where the mutex is locked upon { and unlocked upon } and wait, notify and notifyAll are methods called on a condition variable associated with the mutex.

The important thing to remember is that the mutex can become unlocked within the synchronized block when wait() is called since wait will unlock the mutex and block until notify or notifyAll is called.

Thus, multiple threads can still be blocked within a synchronized block despite the inference that this is not possible.

Update: Annotated code demonstrating this:

Object lock;
// ...
synchronized (lock) { // Underlying mutex is locked.
    // ...
    lock.wait(); // Unlocks mutex, blocks until notify, relocks mutex
    // ...
} // Underlying mutex unlocked

Once lock.wait() is called, other threads are free to enter the synchronized block. They too will block until either a lock.notify() or lock.notifyAll() wakes them.

Categories
discuss

How to import npm module with scoped name installed from github?

I’m trying to install a fork of a github project with npm (at master rather than any specific commit since I want to develop against it):

% npm install parkan/graffiti-mongoose
@risingstack/graffiti-mongoose@2.0.0 node_modules/@risingstack/graffiti-mongoose

This appears to look up the parent repo and install it versioned against master on my gh, so far so good. Note that the package uses scoped package name semantics, which I think is a part of the problem.

% npm list |grep mongoose
├── @risingstack/graffiti-mongoose@2.0.0 (git://github.com/parkan/graffiti-mongoose.git#01a8480fa7d787a4d74bf3bcb257d01b4d73129a)
% ls node_modules/@risingstack/graffiti-mongoose
CHANGELOG.md    LICENSE     fixture
CONTRIBUTING.md README.md   package.json

However, I can’t get node to import or require it in any obvious way:

> require('graffiti-mongoose');
Error: Cannot find module 'graffiti-mongoose'
    at Function.Module._resolveFilename (module.js:336:15)
    at Function.Module._load (module.js:286:25)
    at Module.require (module.js:365:17)
    at require (module.js:384:17)
    at repl:3:1
    at Object.exports.runInThisContext (vm.js:54:17)
    at _eval (/usr/local/lib/node_modules/babel/lib/_babel-node.js:86:26)
    at REPLServer.replEval (/usr/local/lib/node_modules/babel/lib/_babel-node.js:169:14)
    at bound (domain.js:250:14)
    at REPLServer.runBound [as eval] (domain.js:263:12)
> require('@risingstack/graffiti-mongoose');
Error: Cannot find module '@risingstack/graffiti-mongoose'
    at Function.Module._resolveFilename (module.js:336:15)
    at Function.Module._load (module.js:286:25)
    at Module.require (module.js:365:17)
    at require (module.js:384:17)
    at repl:3:1
    at Object.exports.runInThisContext (vm.js:54:17)
    at _eval (/usr/local/lib/node_modules/babel/lib/_babel-node.js:86:26)
    at REPLServer.replEval (/usr/local/lib/node_modules/babel/lib/_babel-node.js:169:14)
    at bound (domain.js:250:14)
    at REPLServer.runBound [as eval] (domain.js:263:12)
> require('risingstack/graffiti-mongoose');
Error: Cannot find module 'risingstack/graffiti-mongoose'
    at Function.Module._resolveFilename (module.js:336:15)
    at Function.Module._load (module.js:286:25)
    at Module.require (module.js:365:17)
    at require (module.js:384:17)
    at repl:3:1
    at Object.exports.runInThisContext (vm.js:54:17)
    at _eval (/usr/local/lib/node_modules/babel/lib/_babel-node.js:86:26)
    at REPLServer.replEval (/usr/local/lib/node_modules/babel/lib/_babel-node.js:169:14)
    at bound (domain.js:250:14)
    at REPLServer.runBound [as eval] (domain.js:263:12)

How do I require a package that’s inside a subdirectory like this?

Answer

This appears to be a bug in npm. Checking out the repo and installing from local filesystem works fine.

Issue filed: https://github.com/npm/npm/issues/9798

EDIT: this appears to be a limitation of installing from github in cases where artifacts aren’t checked in and a prepublish script must run before the module is usable, see https://github.com/npm/npm/issues/3055

Source: stackoverflow
Text is available under the Creative Commons Attribution-ShareAlike License; additional terms may apply. By using this site, you agree to the Privacy Policy, and Copyright Policy. Content is available under CC BY-SA 3.0 unless otherwise noted. The answers/resolutions are collected from stackoverflow, are licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0 © No Copyrights, All Questions are retrived from public domain..