I have a Money class that looks like this (simplified):
public class Money
{
private readonly decimal _amount;
public decimal Amount
{
get { return _amount; }
}
public Money(decimal amount)
{
_amount = amount;
}
public override string ToString()
{
return _amount.ToString("c2");
}
public static implicit operator Money(decimal value)
{
return new Money(value);
}
}
In my Razor view, I want to render a money value like this:
<p>This is my money value:
#Model.MyNullableMoneyValue
</p>
When I run the View, instead of using the Money struct's ToString() method which should result in something like "$10.00", it renders as though it was calling ToString() on the decimal amount, i.e. like "10.0000".
Adding ToString() myself fixes the issue:
<p>This is my money value:
#Model.MyNullableMoneyValue.ToString()
</p>
Why? What's going on?
Related
I have a json which i map to an object as follows:
original json:
{
"amount_predicted" : 1.34
}
mapped:
public class Amount {
#JsonProperty("amount_predicted")
private BigDecimal amountPredicted;
}
I do some work and check this amount and then send this to the client. The issue i have is i want the name of the field to be camelcase on output. But since i already use the json property it wont do that.
This is what id like:
{
"amountPredicted" : 1.34
}
You can annotate the getter and the setter of the amountPredicted field in the Amount class respectively with #JsonProperty("amount_predicted") and #JsonProperty("amountPredicted") annotations thus differentiating the property's name in the deserialization process from the one used for the serialization:
public class Amount {
private BigDecimal amountPredicted;
#JsonProperty("amount_predicted")
public void setAmountPredicted(BigDecimal amountPredicted) {
this.amountPredicted = amountPredicted;
}
#JsonProperty("amountPredicted")
public BigDecimal getAmountPredicted() {
return amountPredicted;
}
}
Amount amount = mapper.readValue(json, Amount.class);
//it will print {"amountPredicted":1.34}
System.out.println(mapper.writeValueAsString(amount));
EDIT: as pointed out by #user1555190 is much simpler to use the JsonAlias annotation:
public class Amount {
#JsonAlias(value = {"amount_predicted"})
private BigDecimal amountPredicted;
}
Issue
There seems to be some issue with this line here family.People.push(people[x]);
I keep getting Member "push" not found or not visible after argument-dependent lookup when I try to compile with brownie.
What have I tried
I saw a few SO posts with similar exceptions but it was related to type casting. I did try to cast my incoming array to its type but it just resulted in more exceptions.
Code
pragma solidity ^0.8.9;
contract Person{
string public FirstName;
string public LastName;
}
contract Family{
Person[] public People;
}
contract FamilyManager{
Family[] Families;
function AddFamily(Person[] memory people) public {
Family family = new Family();
for(uint x; x < people.length; x++){
family.People.push(people[x]);
}
Families.push(family);
}
function GetFamilies() public view returns (Family[] memory){
return Families;
}
}
Can anyone spot what I'm doing wrong here or link to an article that can lead to an answer?
I think it is related to access modifiers. Using the public modifier for your array only generates the getter function for it and not the setter.
As a result, you cannot directly push to an array from another contract. I created a public function to add elements to the array as follows:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
contract Person{
string public FirstName;
string public LastName;
}
contract Family{
Person[] public People;
function addPerson(Person person) public {
People.push(person);
}
}
contract FamilyManager{
Family[] Families;
function AddFamily(Person[] memory people) public {
Family family = new Family();
for(uint x; x < people.length; x++) {
family.addPerson(people[x]);
}
Families.push(family);
}
function GetFamilies() public view returns (Family[] memory){
return Families;
}
}
I want to test a contract where one field is of type java.time.Instant. But not all instances of an Instant are handled as I expect by spring-cloud-contract. Given the following simple contract:
Contract.make {
description("Get a version")
request {
method 'GET'
url '/config/version'
headers {
contentType(applicationJson())
}
}
response {
status 200
body(
nr: 42,
creationDate: producer(anyIso8601WithOffset())
)
headers {
contentType(applicationJson())
}
}
}
And this service implementation:
#RestController
public class VersionController {
#GetMapping(path = "/version")
public ResponseEntity<Version> getCurrentVersion() {
return ResponseEntity.ok(new Version(42, Instant.ofEpochMilli(0)));
}
}
Executing gradle test works fine. But if I replace the Instant with Instant.now(), my provider test fails with
java.lang.IllegalStateException: Parsed JSON [{"nr":42,"creationDate":"2018-11-11T15:28:26.958284Z"}] doesn't match the JSON path [$[?(#.['creationDate'] =~ /([0-9]{4})-(1[0-2]|0[1-9])-(3[01]|0[1-9]|[12][0-9])T(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])(\.\d{3})?(Z|[+-][01]\d:[0-5]\d)/)]]
which is understandable because Instant.now() produces an Instant whose string representation does indeed not match the anyIso8601WithOffset() pattern. But why is this? Why are Instants represented differently and how can I describe a contract that validates for any instant?
Ok, I found a solution that works for me. Although I do not know if this is the way to go.
In order to always get the exact same format of the serialized instant, I define the format of the corresponding property of my version bean as follows:
public class Version {
private final int nr;
private final Instant creationDate;
#JsonCreator
public Version(
#JsonProperty("nr") int nr,
#JsonProperty("creationDate") Instant creationDate)
{
this.nr = nr;
this.creationDate = creationDate;
}
public int getNr() {
return nr;
}
#JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSX", timezone = "UTC")
public Instant getCreationDate() {
return creationDate;
}
}
Im trying to return an sample object from a contract but the data is always blank. Im using the BlockApps WebApi to do the work (http://blockapps.net/documentation). It always just returns a comma seperated string thats blank. Any help?
contract TrackingManager {
Hit[] hits;
function createHit(string _url, string _referrer) {
hits.push(new Hit(_url, _referrer));
}
function getHits() returns (Hit[]) {
return hits;
}
}
contract Hit {
string public url;
string public referrer;
function Hit(string _url, string _referrer) {
url = _url;
referrer = _referrer;
}
}
I may be wrong, but I think it's not possible to return struct arrays yet: http://solidity.readthedocs.io/en/develop/frequently-asked-questions.html and https://github.com/ethereum/cpp-ethereum/issues/1788
//DOC Datatype Constants
public enum DocDatatype {
PROFILE("Profile"),
SUPPORT_DETAIL("SupportDetail"),
MISC_PAGE("MiscPage"),
String name;
DocDatatype(String name) {
this.name = name;
}
public String getName() {
return name;
}
// the identifierMethod
public String toString() {
return name;
}
// the valueOfMethod
public static DocDatatype fromString(String value) {
for (DocDatatype type : DocDatatype.values()) {
if (type.getName().equals(value))
return type;
}
throw new java.lang.IllegalArgumentException(value
+ " is Not valid dmDataType");
}
}
I have written the junit test case in this way. Whether it is right way to write or wrong way...?
public class DocDatatypeTest {
private static final Log logger = LogFactory
.getLog(TreeConstantTest.class);
#Test
public void testDocDatatypeFromName()
{
DocDatatype d= DocDatatype.fromString("Profile");
assertTrue((d.toString().compareToIgnoreCase("PROFILE") == 0));
}
#Test
public void testDocDatatypeFromName1()
{
DocDatatype d = DocDatatype.fromString("SupportDetail");
assertTrue((d.toString().compareToIgnoreCase("SUPPORT_DETAIL") == 0 ));
}
}
}
A few things here:
Remove the logger from the test. A test should pass or fail, no need for logging
Don't use assertTrue for this. If the test fails it will give you no information about /why/ it failed.
I would change this to
#Test
public void testDocDatatypeFromName()
{
DocDatatype actualDocType = DocDatatype.fromString("Profile");
assertSame(DocDataType.PROFILE, actualDocType);
}
If you really want to assert that value of the toString then do this
#Test
public void testDocDatatypeFromName()
{
DocDatatype d= DocDatatype.fromString("Profile");
assertEquals("Profile", d.toString());
}
You're missing tests for when the lookup doesn't match anything
I wouldn't even write these tests as I see them adding no value whatsoever. The code that uses the enums should have the tests, not these.
Your tests are named very badly. There's no need to start a test with test and the fact you add a "1" to the end of the second test should tell you something. Test names should focus on action and behaviour. If you want to read more about this, get the December issue of JAX Magazine which has a snippet about naming from my forthcoming book about testing.