0
votes

I am trying to use a ...ContainingIgnoreCase JPA query to extract the information from three related objects: profile (id), profile_interest (profile_id and interest_id) and interests (id).

In my service I call

@Service public class SearchService {

@Autowired
private ProfileDao profileDao;


public List<SearchResult> search(String text) {
    return profileDao.findByInterestsNameContainingIgnoreCase(text).stream().map(SearchResult::new).collect(Collectors.toList());
}

}

Then my DAO executes it:

Blockquote @Repository public interface ProfileDao extends CrudRepository {

Profile findByUsuario(Usuario usuario);

List<Profile> findByInterestsNameContainingIgnoreCase(String text);

}

My Profile Object:

package music.bolo.domain.entity;

import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Set;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.OneToOne;
import javax.persistence.OrderColumn;
import javax.persistence.Table;

import org.owasp.html.PolicyFactory;

import music.bolo.domain.dto.FileInfo;

@Entity
@Table(name = "profile")
public class Profile {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "id")
    private long id;

    @OneToOne(targetEntity = Usuario.class)
    @JoinColumn(name = "user_id", nullable = false)
    private Usuario usuario;

    @Column(name = "about", length = 5000)
    private String about;

    @Column(name = "photo_directory", length = 10)
    private String photoDirectory;

    @Column(name = "photo_name", length = 10)
    private String photoName;

    @Column(name = "phot_extension", length = 5)
    private String photoExtension;

    @ManyToMany(fetch = FetchType.EAGER)
    @JoinTable(name = "profile_interests", joinColumns = { @JoinColumn(name = "profile_id") }, inverseJoinColumns = {
            @JoinColumn(name = "interest_id") })
    @OrderColumn(name = "display_order")
    private Set<Interest> interests;

    public Profile() {
    }

    public Profile(Usuario usuario) {
        this.usuario = usuario;
    }

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public Usuario getUsuario() {
        return usuario;
    }

    public void setUsuario(Usuario usuario) {
        this.usuario = usuario;
    }

    public String getAbout() {
        return about;
    }

    public void setAbout(String about) {
        this.about = about;
    }

    public String getPhotoDirectory() {
        return photoDirectory;
    }

    public void setPhotoDirectory(String photoDirectory) {
        this.photoDirectory = photoDirectory;
    }

    public String getPhotoName() {
        return photoName;
    }

    public void setPhotoName(String photoName) {
        this.photoName = photoName;
    }

    public String getPhotoExtension() {
        return photoExtension;
    }

    public void setPhotoExtension(String photoExtension) {
        this.photoExtension = photoExtension;
    }

    // Create a profile that is suitable for displaying via JSP
    public void safeCopyFrom(Profile other) {
        if (other.about != null) {
            this.about = other.about;
        }
        if (other.interests != null) {
            this.interests = other.interests;
        }
    }

    // Create a profile sanitized for saving
    public void safeMergeFrom(Profile webProfile, PolicyFactory htmlPolicy) {

        if (webProfile.about != null) {
            this.about = htmlPolicy.sanitize(webProfile.about);
        }
    }

    public void setPhotoDetails(FileInfo info) {

        photoDirectory = info.getSubDirectory();
        photoExtension = info.getExtension();
        photoName = info.getBasename();
    }

    public Path getPhoto(String baseDirectory) {
        if (photoName == null) {
            return null;
        }
        return Paths.get(baseDirectory, photoDirectory, photoName + "." + photoExtension);
    }

    public Set<Interest> getInterests() {
        return interests;
    }

    public void setInterests(Set<Interest> interests) {
        this.interests = interests;
    }

    public void addInterest(Interest interest) {
        interests.add(interest);
    }

    public void removeInterest(String interestName) {
        interests.remove(new Interest(interestName));
    }

    @Override
    public String toString() {
        return "Profile [id=" + id + ", usuario=" + usuario + ", about=" + about + ", photoDirectory=" + photoDirectory
                + ", photoName=" + photoName + ", photoExtension=" + photoExtension + ", interests=" + interests + "]";
    }

}

But... I get this error

2017-01-24 22:06:38.357 INFO 4656 --- [ restartedMain] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default' 2017-01-24 22:06:38.389 INFO 4656 --- [ restartedMain] o.apache.catalina.core.StandardService : Stopping service Tomcat 2017-01-24 22:06:38.404 WARN 4656 --- [ost-startStop-1] o.a.c.loader.WebappClassLoaderBase : The web application [ROOT] appears to have started a thread named [Abandoned connection cleanup thread] but has failed to stop it. This is very likely to create a memory leak. Stack trace of thread: java.lang.Object.wait(Native Method) java.lang.ref.ReferenceQueue.remove(Unknown Source) com.mysql.jdbc.AbandonedConnectionCleanupThread.run(AbandonedConnectionCleanupThread.java:43) 2017-01-24 22:06:38.420 ERROR 4656 --- [ restartedMain] o.s.boot.SpringApplication : Application startup failed

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'indexController': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private music.bolo.services.ProfileService music.bolo.controllers.IndexController.profileService; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'profileService': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: music.bolo.domain.repository.ProfileDao music.bolo.services.ProfileService.profileDao; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'profileDao': Invocation of init method failed; nested exception is java.lang.IllegalStateException: Illegal attempt to dereference path source [null.interests] of basic type at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:334) ~[spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]

1
add your Profile mapping file. Also is the full stack trace? - Maciej Kowalski

1 Answers

0
votes

I solved it using a NAtive Query in my DAO:

package music.bolo.domain.repository;

import java.util.List;

import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.CrudRepository;

import music.bolo.domain.entity.Profile;

public interface ProfileDaoQuery extends CrudRepository {

@Query(value = "SELECT * FROM profile "
        + "INNER JOIN profile_interests ON profile.id = profile_interests.profile_id"
        + " INNER JOIN interests ON profile_interests.interest_id=interests.id "
        + "WHERE interests.interest_name like %?1%", nativeQuery = true)
List<Profile> findByInterestNames(String text);

}