Home > Mobile >  Spring and Hibernate, OneToOne issue
Spring and Hibernate, OneToOne issue

Time:04-12

I've created the Salary object and it was working fine. Then I created the Tax object and tried to create a OneToOne relationship. This has not gone so fine.

Here's my error:

Caused by: org.hibernate.MappingException: Could not determine type for: fyi.incomeoutcome.salarytaxspend.currency.CurrencyConverter, at table: tax, for columns: [org.hibernate.mapping.Column(currency_converter)]

Salary:

package fyi.incomeoutcome.salarytaxspend.salary;

import fyi.incomeoutcome.salarytaxspend.city.City;
import fyi.incomeoutcome.salarytaxspend.role.Role;
import fyi.incomeoutcome.salarytaxspend.salary.salarysite.SalarySite;
import fyi.incomeoutcome.salarytaxspend.tax.Tax;
import lombok.extern.slf4j.Slf4j;

import javax.persistence.*;
import java.util.Date;
import java.util.concurrent.TimeUnit;
//import java.sql.Date;
@Slf4j
@Entity
public class Salary {

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private long id;
    private double compensation;
    @ManyToOne(optional = false)
    @JoinColumn(name = "role_id")
    private Role role;
    @ManyToOne(optional = false)
    @JoinColumn(name = "city_id")
    private City city;
    @ManyToOne(optional = false)
    @JoinColumn(name = "site_id")
    private SalarySite site;
    @OneToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy="salary")
    private Tax tax;
    private String currency;
    private double compensationConverted;

    @Basic
    private java.sql.Date compensationUpdatedOn;

    @Basic
    private java.sql.Date conversionUpdatedOn;

    protected Salary(){}

    public Salary(int compensation, Role role, City city,  SalarySite site, String currency){
        this.compensation = compensation;
        this.role = role;
        this.city = city;
        this.site = site;
        this.currency = currency;
        java.sql.Date today = new java.sql.Date(System.currentTimeMillis());
        this.compensationUpdatedOn = today;
        this.compensationConverted = 0;
        this.conversionUpdatedOn = today;
    }

    public boolean dueNewConversion(){
        if (this.conversionUpdatedOn == null){
            return true;
        }
        Date lastConversionUpdated = new java.util.Date(this.conversionUpdatedOn.getTime());
        Date lastCompensationUpdate = new java.util.Date(this.compensationUpdatedOn.getTime());
        Date today = new Date(System.currentTimeMillis());
        long conversionUpdateDiffInMs = today.getTime() - lastConversionUpdated.getTime();
        long compensationUpdateAgainstConversionUpdate = lastConversionUpdated.getTime() - lastCompensationUpdate.getTime();
        boolean conversionAppliesToPreviousCompensation = compensationUpdateAgainstConversionUpdate < 0;
        long daysSinceLastConversion = TimeUnit.DAYS.convert(conversionUpdateDiffInMs, TimeUnit.MILLISECONDS);
        return (this.compensationConverted == 0 || daysSinceLastConversion > 7 || conversionAppliesToPreviousCompensation);
    }

    public boolean dueNewCompensation(){
        if (this.compensationUpdatedOn == null){
            return true;
        }
        Date lastUpdated = new java.util.Date(this.compensationUpdatedOn.getTime());
        Date today = new Date(System.currentTimeMillis());
        long diffInMs = today.getTime() - lastUpdated.getTime();
        long daysSinceLastConversion = TimeUnit.DAYS.convert(diffInMs, TimeUnit.MILLISECONDS);
        return (daysSinceLastConversion > 183);
    }

    public double getCompensation(){
        return this.compensation;
    }

    public String getCity(){
        return city.getName();
    }

    public String getSeniorityAndRoleName(){
        return role.getSeniorityAndRole();
    }

    public double getCompensationConverted() { return this.compensationConverted; }

    public String getCurrency() { return this.currency.trim(); }

    public void setCompensationConverted(double currencyConverted){
        this.compensationConverted = currencyConverted;
        java.sql.Date today = new java.sql.Date(System.currentTimeMillis());
        this.conversionUpdatedOn = today;
    }

    public String toString(){
        return String.format("Salary[id=%d, currency='%s' compensation=%d, city='%s', role='%s'",
                        id, currency, compensation, city, role);
    }
}

Tax:
package fyi.incomeoutcome.salarytaxspend.tax;
import fyi.incomeoutcome.salarytaxspend.currency.CurrencyConverter;
import fyi.incomeoutcome.salarytaxspend.salary.Salary;

import fyi.incomeoutcome.salarytaxspend.tax.taxsite.TaxSite;
import fyi.incomeoutcome.salarytaxspend.tax.taxsite.TaxSiteRepository;
import lombok.extern.slf4j.Slf4j;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.Keys;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.springframework.beans.factory.annotation.Autowired;
import javax.persistence.*;

import io.github.bonigarcia.wdm.WebDriverManager;

import java.util.Locale;

@Slf4j
@Entity
public class Tax {

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private long id;

    @OneToOne(fetch = FetchType.EAGER, optional = false)
    @JoinColumn(name = "salary_id", nullable = false)
    private Salary salary;
    private double taxPayable;
    private double taxPayableConverted;

    @Autowired
    CurrencyConverter currencyConverter;
    @Autowired
    TaxSiteRepository taxSiteRepository;

    public Tax(Salary salary){
        this.salary = salary;
        this.taxPayable = calculateTaxPayable();
        this.taxPayableConverted = convertTaxPayableToEuro();
    }

    private double calculateTaxPayable(){
        WebDriverManager.chromedriver().setup();
        ChromeDriver driver = new ChromeDriver();
        TaxSite taxSite = taxSiteRepository.findById(1);
        String taxSiteUrl = taxSite.getUrlBase()   salary.getCity().toLowerCase()   taxSite.getUrlEnd();
        driver.get(taxSiteUrl);
        WebElement salaryInput = driver.findElement(By.id("j2"));
        JavascriptExecutor jExec = (JavascriptExecutor) driver;
        String executionScript = String.format("arguments[0].value='%s';", this.salary.getCompensation());
        jExec.executeScript(executionScript, salaryInput);
        salaryInput.sendKeys(Keys.RETURN);
        String taxPayableXPath = "//*[@id=\"taxResults\"]/table[1]/tbody/tr[4]/td[1]";
        Double taxPayable = Double.parseDouble(driver.findElement(By.xpath(taxPayableXPath)).getText());
        log.info(String.format("For %s Tax payable is : %d", this.salary, taxPayable));
        return taxPayable;
    }

    private double convertTaxPayableToEuro(){
        double convertedTax = currencyConverter.convertFigureToEuro(this.taxPayable, this.salary.getCurrency());
        return convertedTax;
    }
}
----------------------------------
CurrencyConverter:
package fyi.incomeoutcome.salarytaxspend.currency;

import fyi.incomeoutcome.salarytaxspend.currency.currencysite.CurrencySite;
import fyi.incomeoutcome.salarytaxspend.currency.currencysite.CurrencySiteRepository;
import fyi.incomeoutcome.salarytaxspend.salary.Salary;
import fyi.incomeoutcome.salarytaxspend.salary.SalaryRepository;
import lombok.extern.slf4j.Slf4j;
import org.json.JSONArray;
import org.json.JSONObject;
import org.jsoup.Jsoup;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.Iterator;
import java.util.List;


@Slf4j
@Component
public class CurrencyConverter {

    @Autowired
    private CurrencySiteRepository currencySiteRepository;
    @Autowired
    private CurrencyRepository currencyRepository;


    public double convertSalaryToEuro(Salary salary){
        String currencyUsed = salary.getCurrency();
        double compensation = salary.getCompensation();
        if (currencyUsed.equals("€")){
            return compensation;
        }
        return convertFigureToEuro(compensation, currencyUsed);
    }

    public double convertFigureToEuro(double figure, String currencyUsed){
        var currencyNeededOptional = currencyRepository.findByCurrencyCode(currencyUsed);
        if (!currencyNeededOptional.isPresent()){
            saveCurrencyRates();
            currencyNeededOptional = currencyRepository.findByCurrencyCode(currencyUsed);
        }
        Currency currencyNeeded = currencyNeededOptional.get();
        double currencyRate = currencyNeeded.getConversionRate();
        return figure / currencyRate;
    }
    public void saveCurrencyRates(){
        long currencySiteId = 1;
        CurrencySite currencySite = currencySiteRepository.findById(currencySiteId);
        String dataKey = currencySite.getJsonResultDataKey();
        String currencySiteUrl = currencySite.getCurrencyUrl();
        String currencyResults = "NA";
        try {
            currencyResults = Jsoup.connect(currencySiteUrl).ignoreContentType(true).get().body().text();
        } catch (IOException e) {
            e.printStackTrace();
        }
        JSONObject currencyResultsJson = new JSONObject(currencyResults).getJSONObject(dataKey);
        Iterator<String> keys = currencyResultsJson.keys();
        while(keys.hasNext()){
            String key = keys.next();
            log.info(String.valueOf(currencyResultsJson.get(key)));
            JSONObject currencyEntry = (JSONObject) currencyResultsJson.get(key);
            log.info(String.valueOf(currencyEntry));
            String currencyCode = (String) currencyEntry.get("code");
            if (currencyCode.equals("EUR")){
                continue;
            }
            BigDecimal currencyRate = (BigDecimal) currencyEntry.get("value");
            double currencyRateDouble = currencyRate.doubleValue();
            log.info(String.format("Currency code, rate : %s %s", currencyCode, currencyRateDouble));
            Currency generatedCurrency = new Currency(currencyCode, currencyRateDouble);
            currencyRepository.save(generatedCurrency);

        }
        //return currencyResultsJson;
    }
}

CodePudding user response:

Normally in entity we will maintain only the Relationship and the fields. The Autowired and other business logic should be maitained in the service class.

Dont use these Autowire in entity class, so because of using it - its considering those as a column / field. Becuase Autowired are maintained by SpringIOC and entity are used to manage the db related operations. Ref : https://stackoverflow.com/questions/54014047/can-we-use-autowired-on-an-entity-object-in-spring#:~:text=You can only autowire only,@Service , @Repository etc.

 @Autowired
    CurrencyConverter currencyConverter;
    @Autowired
    TaxSiteRepository taxSiteRepository;

CodePudding user response:

@OneToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "salary_id", referencedColumnName = "id")
    private Salary salary;
@OneToOne(mappedBy = "salary")
    private Tax tax;

use this reference : https://www.baeldung.com/jpa-one-to-one

  • Related